本篇文章是深入理解Terraform系列的第一部分。在介紹文章中,我們討論了為什么每家互聯(lián)網(wǎng)軟件公司都應(yīng)該使用基礎(chǔ)設(shè)施即代碼(IAC)。那么本篇,我們打算討論下為什么我們選擇Terraform 作為我們的IAC 工具。 如果你在網(wǎng)上搜索“instrastructure-as-code”,很容易看到很多受歡迎的工具:
篩選出它們中你應(yīng)該使用哪個(gè)不是很容易。所有這些上述工具都可以用于基礎(chǔ)設(shè)施即代碼。它們都是開源的,背靠龐大的貢獻(xiàn)者社區(qū),可以很好配合各種不同的云服務(wù)商。它們都提供商業(yè)支持,提供良好的文檔——在官方文檔和社區(qū)資源方面(比如博客文章和StackOverflow問答)。 更難以理解的是,您在這些工具之間在線找到的大多數(shù)比較只是列出每個(gè)工具的一般屬性,并使其聽起來像您可以同樣成功地使用它們中的任何一個(gè)。雖然這在技術(shù)上是正確的,但它沒有幫助。就像告訴一個(gè)程序員新手你可以用PHP,C,匯編都可以創(chuàng)建網(wǎng)站。這個(gè)聲明在技術(shù)上是正確的,但卻省略了大量的信息,這些信息對(duì)于做出正確的決定非常有用。 本篇文章,我們會(huì)分成幾個(gè)特定原因來解釋為什么我們會(huì)選擇Terraform作為IAC工具。與所有技術(shù)決策一樣,這是一個(gè)權(quán)衡和優(yōu)先級(jí)的問題,雖然您的特定優(yōu)先級(jí)可能與我們的不同,但我們希望分享我們的思維過程將幫助您做出自己的決定。以下是我們考慮的主要權(quán)衡因素:
配置管理 vs 配置Chef, Puppet, Ansible, and SaltStack 都是配置管理工具,這意味著它們?cè)O(shè)計(jì)初衷都是在現(xiàn)有的服務(wù)器上安裝和管理軟件。CloudFormation 和 Terraform 是配置(provisioning)工具,這意味這它們的設(shè)計(jì)初衷是配置服務(wù)器本身的(以及基礎(chǔ)設(shè)施的其他部分,比如負(fù)載均衡器,數(shù)據(jù)庫(kù),網(wǎng)絡(luò)配置等),將配置這些服務(wù)器的工作留給其他工具。這兩類工具互相不排斥的。因?yàn)榇蠖鄶?shù)配置管理工具可以在某種程度上多一些配置工作而大多數(shù)配置工具也可以在某種程度上做配置管理的工作。但是聚焦于配置管理或者配置意味著,這些工具對(duì)于特定類型的任務(wù)會(huì)更加合適。 特別指出,我們發(fā)現(xiàn)如果你使用Docker 或者 Packer,更加需要關(guān)注配置管理。使用Docker 或者Packer,你可以創(chuàng)建所需軟件已經(jīng)安裝或者配置了的鏡像。一旦你有這樣一個(gè)鏡像,你所需要做的就是運(yùn)行它。如果你所需要做的是配置一組服務(wù)器,那么想Terraform這樣的配置工具會(huì)比配置管理工具更加適合。 可變基礎(chǔ)設(shè)施 vs 不可變基礎(chǔ)設(shè)施想Chef,Puppt,Ansible 這樣的配置管理工具默認(rèn)針對(duì)一種可變的基礎(chǔ)設(shè)施范例。比如,如果你告訴Chef 安裝一個(gè)新版本的OpenSSL,它就會(huì)在你現(xiàn)有的服務(wù)器上運(yùn)行軟件更新并且就地生效。隨著時(shí)間推移,你會(huì)更新的更多,每臺(tái)服務(wù)器都會(huì)構(gòu)建一個(gè)唯一的修改歷史。這通常會(huì)導(dǎo)致稱為配置漂移或者誤差的現(xiàn)象,其中每個(gè)服務(wù)器與所有其他服務(wù)器略有不同,導(dǎo)致難以診斷且?guī)缀醪豢赡茉佻F(xiàn)的細(xì)微配置錯(cuò)誤。 如果你正在使用像Terraform這樣的配置工具來部署由Docker 或者 Packer創(chuàng)建的鏡像,那么每次"修改"事實(shí)上都是一次新服務(wù)器的部署(就像是函數(shù)式編程中每次變量的修改事實(shí)上會(huì)返回新的變量)。比如,當(dāng)我們部署一個(gè)新版本的OpenSSL,你會(huì)用裝有新版本OpenSSL的Packer或者Docker來創(chuàng)建鏡像,然后在整組新服務(wù)器中部署那個(gè)鏡像,同時(shí)卸載老的鏡像。這種方法減少了配置偏差問題的可能性,使得了解服務(wù)器上運(yùn)行了哪些軟件變得更加容易,同時(shí)可以讓你任何時(shí)候都可以輕松部署任何版本的軟件。當(dāng)然,也可以強(qiáng)制配置管理工具來做不可變部署。但是對(duì)這些工具來說,這不是慣用的方式。不管怎樣,使用配置工具都是一種更加自然的方式。 程式化 vs 可聲明化Chef和Ansible鼓勵(lì)一種程序風(fēng)格,您可以編寫代碼,逐步指定如何實(shí)現(xiàn)預(yù)期狀態(tài)。 Terraform,CloudFormation,SaltStack和Puppet都鼓勵(lì)更具說明性的風(fēng)格,您可以編寫指定所需最終狀態(tài)的代碼,IAC工具本身負(fù)責(zé)確定如何實(shí)現(xiàn)該狀態(tài)。 例如,假設(shè)您要部署10臺(tái)服務(wù)器(AWS術(shù)語(yǔ)中的“EC2 Instances”)來運(yùn)行應(yīng)用程序的v1版本。以下是使用過程方法執(zhí)行此操作的Ansible模板的簡(jiǎn)化示例:
以下是使用聲明方法執(zhí)行相同操作的Terraform模板的簡(jiǎn)化示例:
表面上看,這兩種方法可能看起來相似,當(dāng)您最初使用Ansible或Terraform執(zhí)行它們時(shí),它們將產(chǎn)生類似的結(jié)果。有趣的是,當(dāng)您想要進(jìn)行更改時(shí)會(huì)發(fā)生什么。 例如,假設(shè)流量增加,并且您希望將服務(wù)器數(shù)量增加到15。使用Ansible,您之前編寫的過程代碼就沒法使用了;如果您剛剛將服務(wù)器數(shù)量更新為15并重新啟動(dòng)該代碼,那么它將部署15臺(tái)新服務(wù)器,總共25臺(tái)服務(wù)器!因此,您必須了解已部署的內(nèi)容并編寫一個(gè)全新的過程腳本來添加5臺(tái)新服務(wù)器:
使用聲明性代碼,因?yàn)槟闼龅木褪锹暶髂阆胍淖罱K狀態(tài),而Terraform計(jì)算出如何到達(dá)那個(gè)最終狀態(tài),Terraform也會(huì)知道它過去創(chuàng)建的任何狀態(tài)。因此,要部署另外5臺(tái)服務(wù)器,你所作的只需要返回到之前相同的Terraform模板并將計(jì)數(shù)從10更新為15:
如果你執(zhí)行了這個(gè)模板,Terraform會(huì)意識(shí)到它已經(jīng)創(chuàng)建了10個(gè)服務(wù)器,因此它需要做的只是創(chuàng)建5個(gè)新服務(wù)器。實(shí)際上,在運(yùn)行此模板之前,您可以使用Terraform的plan命令來預(yù)覽它將進(jìn)行的更改:
現(xiàn)在,當(dāng)您想要部署v2服務(wù)時(shí)會(huì)發(fā)生什么? 使用過程方法,您之前的兩個(gè)Ansible模板都沒有用,所以您必須編寫另一個(gè)模板來跟蹤之前部署的10個(gè)服務(wù)器(或者現(xiàn)在是15個(gè)?)并仔細(xì)更新每個(gè)模板到新版本。 使用Terraform的聲明式方法,您可以再次返回完全相同的模板,只需將ami版本號(hào)更改為v2:
顯然,上述例子是簡(jiǎn)化的。 Ansible允許您在部署新的EC2實(shí)例之前使用標(biāo)簽來搜索現(xiàn)有的EC2實(shí)例(例如,使用instance_tags和count_tag參數(shù)),但是必須根據(jù)每個(gè)資源的情況為Ansible管理的每個(gè)資源手動(dòng)找出這種邏輯。 過去的歷史,可能會(huì)令人驚訝地復(fù)雜化(例如,不僅通過標(biāo)簽,還可以通過圖像版本,可用區(qū)域等查找現(xiàn)有實(shí)例)。 這突出了程序IAC工具的兩個(gè)主要問題:
另一方面,在Terraform中使用的這種聲明式方法,代碼始終代表基礎(chǔ)架構(gòu)的最新狀態(tài)。 一目了然,您可以分辨當(dāng)前部署的內(nèi)容及其配置方式,而無需擔(dān)心歷史記錄或時(shí)間安排。 這也使得創(chuàng)建可重用代碼變得容易,因?yàn)槟槐厥謩?dòng)考慮當(dāng)前的世界狀態(tài)。 相反,您只需專注于描述您想要的狀態(tài),Terraform會(huì)自動(dòng)確定如何從一個(gè)狀態(tài)到另一個(gè)狀態(tài)。 因此,Terraform代碼庫(kù)往往保持小巧且易于理解。 當(dāng)然,聲明性語(yǔ)言也有缺點(diǎn)。 如果無法使用完整的編程語(yǔ)言,您的表達(dá)能力就會(huì)受到限制。 例如,某些類型的基礎(chǔ)設(shè)施更改(例如回滾,零停機(jī)時(shí)間部署)很難用純粹的聲明性術(shù)語(yǔ)表達(dá)。 同樣,如果沒有“邏輯”(例如if語(yǔ)句,循環(huán))的能力,創(chuàng)建通用的,可重用的代碼可能會(huì)很棘手(特別是在CloudFormation中)。 幸運(yùn)的是,Terraform提供了許多強(qiáng)大的原語(yǔ),例如輸入變量,輸出變量,模塊,create_before_destroy和count,這使得即使在聲明性語(yǔ)言中也可以創(chuàng)建干凈,可配置的模塊化代碼。 我們將在第4部分,如何使用Terraform模塊創(chuàng)建可重用的基礎(chǔ)架構(gòu)和第5部分,Terraform提示和技巧:循環(huán),if語(yǔ)句和陷阱中更多地討論這些工具。 Master vs Masterless默認(rèn)情況下,Chef,Puppet和SaltStack都要求您運(yùn)行主服務(wù)器以存儲(chǔ)基礎(chǔ)設(shè)施的狀態(tài)并分發(fā)更新。 每次要更新基礎(chǔ)設(shè)施中的某些內(nèi)容時(shí),都使用客戶端(例如,命令行工具)向主服務(wù)器發(fā)出新命令,主服務(wù)器將更新推送到所有其他服務(wù)器或那些服務(wù)器定期從主服務(wù)器中提取最新的更新。 主服務(wù)器提供了一些優(yōu)點(diǎn)。 首先,它是一個(gè)單一的中心位置,您可以在其中查看和管理基礎(chǔ)設(shè)施的狀態(tài)。 許多配置管理工具甚至為主服務(wù)器提供Web界面(例如,Chef Console,Puppet Enterprise Console),以便更容易查看正在發(fā)生的事情。 其次,一些主服務(wù)器可以在后臺(tái)連續(xù)運(yùn)行,并強(qiáng)制執(zhí)行您的配置。 這樣,如果有人在服務(wù)器上進(jìn)行手動(dòng)更改,主服務(wù)器可以還原該更改以防止配置偏移。 但是,必須運(yùn)行主服務(wù)器有一些嚴(yán)重的缺點(diǎn):
Chef,Puppet和SaltStack對(duì)無主模式有不同程度的支持,您只需在每個(gè)服務(wù)器上運(yùn)行代理軟件,通常在一定周期內(nèi)(例如,每5分鐘運(yùn)行一次的cron作業(yè)),并使用它從版本控制(而不是從主服務(wù)器)下拉最新更新。 這顯著減少了變動(dòng)的次數(shù),但是,如下一節(jié)所述,這仍然留下了許多未答復(fù)的問題,尤其是關(guān)于如何配置服務(wù)器以及首先在其上安裝代理軟件的問題。 Ansible,CloudFormation,Heat和Terraform默認(rèn)都是無主的。 或者,更準(zhǔn)確一些,它們中的一些可能依賴于主服務(wù)器,但它已經(jīng)是您正在使用的基礎(chǔ)設(shè)施的一部分,而不是您必須管理的額外部分。 例如,Terraform使用云提供商的API與云提供商進(jìn)行通信,因此在某種意義上,API服務(wù)器是主服務(wù)器,除了它們不需要任何額外的基礎(chǔ)設(shè)施或任何額外的認(rèn)證機(jī)制(即,只使用您的API密鑰)。 Ansible的工作方式是通過SSH直接連接到每個(gè)服務(wù)器,因此,您不必再運(yùn)行任何額外的基礎(chǔ)結(jié)構(gòu)或管理額外的身份驗(yàn)證機(jī)制(即只使用SSH密鑰)。 Agent vs AgentlessChef,Puppet和SaltStack都要求您在要配置的每臺(tái)服務(wù)器上安裝代理軟件(例如,Chef Client,Puppet Agent,Salt Minion)。 代理通常在每個(gè)服務(wù)器的后臺(tái)運(yùn)行并負(fù)責(zé) 安裝最新的配置管理更新。 這有一些缺點(diǎn):
再?gòu)?qiáng)調(diào)一次,Chef,Puppet和SaltStack都對(duì)無代理模式(例如,salt-ssh)有不同程度的支持,但是這些通常感覺它們是作為事后的想法加入的,并不總是支持完整的配置管理工具的功能集。這就是為什么Chef,Puppet和SaltStack的默認(rèn)或慣用配置幾乎總是包含一個(gè)代理,通常也包含一個(gè)master。 所有這些額外的動(dòng)態(tài)部分都會(huì)在您的基礎(chǔ)架構(gòu)中引入大量新的故障模式。 每次凌晨3點(diǎn)收到錯(cuò)誤報(bào)告時(shí),您都必須弄清楚它是否是應(yīng)用程序代碼,IAC代碼,配置管理客戶端,主服務(wù)器或者服務(wù)器中的錯(cuò)誤。 客戶端與主服務(wù)器通信,或者其他服務(wù)器與主服務(wù)器通信的方式,或者...... Ansible,CloudFormation,Heat和Terraform不要求您安裝任何額外的代理。 或者,更準(zhǔn)確一些,它們中的一些需要代理,但這些代理通常已作為您正在使用的基礎(chǔ)結(jié)構(gòu)的一部分安裝。 例如,AWS,Azure,Google Cloud和所有其他云提供商負(fù)責(zé)在每臺(tái)物理服務(wù)器上安裝,管理和驗(yàn)證代理軟件。 作為Terraform的用戶,您不必?fù)?dān)心任何問題:您只需發(fā)出命令然后云服務(wù)商會(huì)在所有你的服務(wù)器上為你執(zhí)行它們。 使用Ansible,您的服務(wù)器需要運(yùn)行SSH守護(hù)程序,不管怎么樣,這都會(huì)普遍運(yùn)行在大多數(shù)服務(wù)器上的。 成熟與前沿選擇任何技術(shù)時(shí)要考慮的另一個(gè)關(guān)鍵因素是成熟度。 下表顯示了每個(gè)IAC工具的初始發(fā)布日期和當(dāng)前版本號(hào)(截至2019年5月)。 同樣,這不是一個(gè)同類的比較,因?yàn)椴煌墓ぞ哂胁煌陌姹究刂品桨?,但一些趨?shì)是明確的。 到目前為止,Terraform是此比較中最年輕的IAC工具。 它仍然是處于1.0.0版本之前,因此無法保證穩(wěn)定或向后兼容的API,并且錯(cuò)誤相對(duì)常見(盡管大多數(shù)都是次要的)。 這是Terraform最大的弱點(diǎn):雖然它在短時(shí)間內(nèi)變得非常受歡迎,但使用這種新的尖端工具所付出的代價(jià)是它不像其他一些IAC選項(xiàng)那樣成熟。 混合使用多種工具雖然我一直在比較整個(gè)博客文章中的IAC工具,但事實(shí)是您可能需要使用多種工具來構(gòu)建您的基礎(chǔ)設(shè)施。 您看到的每個(gè)工具都有優(yōu)點(diǎn)和缺點(diǎn),因此您需要為正確的工作選擇合適的工具。 以下是我見過的三種常見組合在很多公司都很好用:
配置 + 配置管理 示例:Terraform和Ansible。 您可以使用Terraform部署所有底層基礎(chǔ)設(shè)施,包括網(wǎng)絡(luò)拓?fù)洌碫PC,子網(wǎng),路由表),數(shù)據(jù)存儲(chǔ)(例如,MySQL,Redis),負(fù)載均衡器和服務(wù)器。 然后,您使用Ansible在這些服務(wù)器之上部署您的應(yīng)用程序。 這是一個(gè)簡(jiǎn)單的方法,因?yàn)闆]有運(yùn)行額外的基礎(chǔ)設(shè)施(Terraform和Ansible都是客戶端應(yīng)用程序),并且有很多方法可以使Ansible和Terraform一起工作(例如,Terraform為您的服務(wù)器添加特殊標(biāo)簽然后Ansible使用這些標(biāo)簽來查找服務(wù)器并對(duì)其進(jìn)行配置。 主要缺點(diǎn)是使用Ansible通常意味著您編寫了大量程序式代碼,使用可變服務(wù)器,因此隨著代碼庫(kù),基礎(chǔ)架構(gòu)和團(tuán)隊(duì)的增長(zhǎng),維護(hù)可能會(huì)變得更加困難。 配置 + 服務(wù)器模板 示例:Terraform和Packer。您使用Packer將應(yīng)用程序打包為虛擬機(jī)鏡像。然后使用Terraform部署(a)具有這些虛擬機(jī)鏡像的服務(wù)器和(b)基礎(chǔ)架構(gòu)的其余部分,包括網(wǎng)絡(luò)拓?fù)洌碫PC,子網(wǎng),路由表),數(shù)據(jù)存儲(chǔ)(例如,MySQL,Redis),和負(fù)載均衡器。 這也是一種簡(jiǎn)單的方法,因?yàn)闆]有運(yùn)行額外的基礎(chǔ)設(shè)施(Terraform和Packer都是僅客戶端應(yīng)用程序)。此外,這是一種不可變的基礎(chǔ)架構(gòu)方法,這將使維護(hù)更容易。但是,有兩個(gè)主要缺點(diǎn)。首先,虛擬機(jī)可能需要很長(zhǎng)時(shí)間才能構(gòu)建和部署,這會(huì)降低迭代速度。其次,您可以使用Terraform實(shí)施的部署策略是有限的(例如,您無法在Terraform中本地實(shí)施藍(lán)綠色部署),因此您要么最終編寫大量復(fù)雜的部署腳本,要么轉(zhuǎn)向編排工具,如下所述。 配置 + 服務(wù)器模板 + 編排 示例:Terraform,Packer,Docker和Kubernetes。 您使用Packer創(chuàng)建安裝了Docker和Kubernetes的虛擬機(jī)映像。 然后使用Terraform部署(a)服務(wù)器集群,每個(gè)服務(wù)器運(yùn)行此虛擬機(jī)鏡像,以及(b)基礎(chǔ)架構(gòu)的其余部分,包括網(wǎng)絡(luò)拓?fù)洌碫PC,子網(wǎng),路由表),數(shù)據(jù)存儲(chǔ)( 例如,MySQL,Redis)和負(fù)載均衡器。 最后,當(dāng)服務(wù)器集群?jiǎn)?dòng)時(shí),它形成一個(gè)Kubernetes集群,用于運(yùn)行和管理Dockerized應(yīng)用程序。 這種方法的優(yōu)點(diǎn)是Docker鏡像構(gòu)建相當(dāng)快,您可以在本地計(jì)算機(jī)上運(yùn)行和測(cè)試它們,并且您可以利用Kubernetes的所有內(nèi)置功能,包括各種部署策略,自動(dòng)修復(fù),自動(dòng)縮放, 等等。 缺點(diǎn)是增加了復(fù)雜性,無論是在運(yùn)行額外的基礎(chǔ)設(shè)施方面(Kubernetes集群都很難部署和運(yùn)營(yíng),盡管大多數(shù)主要的云提供商現(xiàn)在提供托管的Kubernetes服務(wù),可以減輕部分工作),還是學(xué)習(xí)、管理和debug額外的抽象層(Kubernetes,Docker,Packer)方面。 總結(jié)我們想要的是一個(gè)開源的,與云無關(guān)的配置工具,它支持不可變基礎(chǔ)架構(gòu),一種聲明性語(yǔ)言和僅客戶端架構(gòu)。 從上表中可以看出,Terraform是唯一符合我們所有標(biāo)準(zhǔn)的工具。 它當(dāng)然不是完美的,特別是在成熟度方面,但我們發(fā)現(xiàn)Terraform的優(yōu)勢(shì)遠(yuǎn)遠(yuǎn)超過它的弱點(diǎn),并且沒有其他IAC工具能夠滿足我們的標(biāo)準(zhǔn)。
|
|