不可變基礎(chǔ)設(shè)施的構(gòu)想
如果需要修改或升級(jí)某些實(shí)例,唯一的方式就是創(chuàng)建一批新的實(shí)例以替換。這種思想與不可變對(duì)象的概念是完全相同的。
實(shí)現(xiàn)這種模式的好處是顯而易見(jiàn)的,這意味著配置工作可實(shí)現(xiàn)重復(fù)性,減少了配置管理工作的負(fù)擔(dān),讓持續(xù)集成與持續(xù)部署過(guò)程變得更流暢。同時(shí)它也更易于應(yīng)對(duì)部署環(huán)境間的差異及版本管理,包括在部署出錯(cuò)時(shí)可進(jìn)行快速回滾 ——只要舊版本的鏡像文件還有備份,就可以快速地生成舊版本的實(shí)例進(jìn)行替換。否則的話(huà),就只能老老實(shí)實(shí)地重新構(gòu)建舊版本的實(shí)例,并且祈禱能夠趕在老板掀桌之前完成回滾。
實(shí)現(xiàn)這一模式需要滿(mǎn)足兩點(diǎn)基本需求,首先應(yīng)用程序必須是無(wú)狀態(tài)的,不可依賴(lài)于本地的文件上傳、會(huì)話(huà)與緩存?;旧希绻麘?yīng)用程序要實(shí)現(xiàn)負(fù)載均衡,都必須滿(mǎn)足這一點(diǎn)。而更重要的一點(diǎn)是,能夠通過(guò)某種模板(或指令)將實(shí)例快速地部署到生產(chǎn)環(huán)境中。后一點(diǎn)無(wú)疑是關(guān)鍵所在,也是這一模式的最大挑戰(zhàn)。
雖然這種模式能夠帶來(lái)很大的好處,但實(shí)現(xiàn)它的難度也是很高的,傳統(tǒng)的虛擬化技術(shù)在應(yīng)對(duì)這一模式時(shí)顯得有些力不從心。幸運(yùn)的是,DevOps社區(qū)發(fā)現(xiàn)Docker(或者說(shuō)容器)正是實(shí)現(xiàn)這一模式的優(yōu)秀選擇。
使用容器實(shí)現(xiàn)不可變基礎(chǔ)設(shè)施
來(lái)自Tutum的Fernando Mayo近期在一篇博客中詳細(xì)地論述了使用容器技術(shù)實(shí)現(xiàn)不可變基礎(chǔ)設(shè)施的優(yōu)點(diǎn)。他首先指出,容器并不是實(shí)現(xiàn)這一模式的唯一選擇,使用虛擬機(jī)模板、或者通過(guò)Chef與Puppet這樣的配置管理工具同樣可以實(shí)現(xiàn)這一目的。但這些方式都面臨著一些負(fù)面因素,前者需要為不同的云環(huán)境創(chuàng)建針對(duì)不同版本的大量虛擬機(jī)模板,后者則需要對(duì)配置管理腳本進(jìn)行持續(xù)地測(cè)試,其負(fù)擔(dān)是顯而易見(jiàn)的。
Fernando推薦使用容器作為實(shí)現(xiàn)不可變基礎(chǔ)設(shè)施的途徑,因?yàn)橥ㄟ^(guò)它進(jìn)行實(shí)例創(chuàng)建、測(cè)試與部署比起虛擬機(jī)與配置腳本快得多。而且使用容器能夠消除應(yīng)用程序依賴(lài)的問(wèn)題,因?yàn)樗械囊蕾?lài)都與應(yīng)用程序一起封裝在容器中,因而進(jìn)一步縮短了整體部署時(shí)間。同時(shí),容器也解決了對(duì)特定云環(huán)境的依賴(lài),只要能夠運(yùn)行Docker,無(wú)論是哪種Linux環(huán)境都可以一視同仁(Windows Server也快了)。
接下來(lái)要做的是使用容器實(shí)現(xiàn)自動(dòng)化的部署,包含兩個(gè)步驟。第一步是創(chuàng)建容器鏡像文件,F(xiàn)ernando推薦使用經(jīng)優(yōu)化的Dockerfile,這種方式非常簡(jiǎn)便快速,可以在持續(xù)集成或持續(xù)交付平臺(tái)中對(duì)其進(jìn)行測(cè)試后再進(jìn)行部署。第二步就是最后的部署工作了,常見(jiàn)的做法是手動(dòng)將容器部署到服務(wù)器上,然后將負(fù)載均衡器指向這些服務(wù)器以接受用戶(hù)訪(fǎng)問(wèn)。這一點(diǎn)可在實(shí)例級(jí)別實(shí)現(xiàn)(例如在每個(gè)AWS EC2實(shí)例中配置一個(gè)應(yīng)用程序的容器,通過(guò)Elastic Load Balancer在實(shí)例間進(jìn)行切換),也可以在容器級(jí)別實(shí)現(xiàn)(通過(guò)Haproxy或Nginx容器將訪(fǎng)問(wèn)轉(zhuǎn)發(fā)到應(yīng)用程序容器)。那么如何通過(guò)自動(dòng)化方式完成第二步呢?Fernando在此推薦了自家的產(chǎn)品Tutum!
使用Tutum實(shí)現(xiàn)容器的自動(dòng)化部署
Tutum為Docker容器提供了托管服務(wù),通過(guò)使用Tutum,部署應(yīng)用程序的新版本變成了一件非常簡(jiǎn)單的任務(wù),只需在服務(wù)定義中修改鏡像的標(biāo)簽,然后點(diǎn)擊“重新部署”即可。
而在非生產(chǎn)環(huán)境中(例如QA或UAT環(huán)境),回滾到應(yīng)用程序的某個(gè)特定版本并不是非常重要的任務(wù),這種情況下甚至可以選擇對(duì)“重新部署”進(jìn)行自動(dòng)化,可以通過(guò)使用Tutum的“自動(dòng)重新部署”特性,或使用DockerHub的重新部署觸發(fā)器。
在重新部署流程啟動(dòng)之后,Tutum將會(huì)逐個(gè)地用新的容器替換舊的容器,隨后通過(guò)tutum/haproxy鏡像實(shí)現(xiàn)訪(fǎng)問(wèn)的轉(zhuǎn)發(fā),這個(gè)鏡像會(huì)根據(jù)所鏈接的容器進(jìn)行自動(dòng)配置。這種方式還能夠?qū)崿F(xiàn)新版本與舊版本的服務(wù)的同時(shí)運(yùn)行,只需在tutum/haproxy服務(wù)中添加一個(gè)到新鏡像的鏈接就可以將訪(fǎng)問(wèn)同時(shí)轉(zhuǎn)發(fā)給新版本與舊版本的服務(wù)。
Tutum還能夠?qū)崿F(xiàn)數(shù)據(jù)卷的重用,因?yàn)樵诙啻尾渴鹬g的數(shù)據(jù)卷是持久化的。如果你重新部署了一個(gè)tutum/mysql容器,它就會(huì)自動(dòng)在/var/lib/mysql路徑下創(chuàng)建一個(gè)數(shù)據(jù)卷,Tutum將重用這個(gè)數(shù)據(jù)卷,并保持所有數(shù)據(jù)不會(huì)丟失。
來(lái)自社區(qū)的其它聲音
雖然Docker為代碼的部署與不可變環(huán)境的創(chuàng)建提供了一個(gè)堅(jiān)實(shí)的基礎(chǔ),但人們也開(kāi)始反思:絕對(duì)的不可變性是否能夠應(yīng)對(duì)應(yīng)用程序的復(fù)雜性與多樣性?就在去年,Docker推出了一個(gè)新的特性,允許“可寫(xiě)的 /etc/hosts,/etc/hostname,以及/etc/resolv.conf”,這就意味著可以對(duì)運(yùn)行中的容器進(jìn)行修改。這不由令人心生疑惑,難道Docker打算遠(yuǎn)離“不可變基礎(chǔ)設(shè)施”這一思想,還是說(shuō)這一思想本身尚有不足之處?
對(duì)此,VisualOps的創(chuàng)始人兼CEO趙鵬在一篇博客中表達(dá)了他的觀點(diǎn),他認(rèn)為Docker雖然能夠跨多個(gè)不同的部署平臺(tái)保證一致性,但許多配置信息是特定于上下文的,因此不必死守純粹的不可變性這一思想。而Docker的這一特性能夠避免配置信息對(duì)于代碼及應(yīng)用程序產(chǎn)生的侵入性,可以通過(guò)某種編排工具使用這一特性,在運(yùn)行時(shí)對(duì)應(yīng)用程序進(jìn)行特定的配置。
而來(lái)自Chef的產(chǎn)品經(jīng)理Julian Dunn也表達(dá)了類(lèi)似的看法,他認(rèn)為純粹的不可變性既不實(shí)際,也并非一種理想狀態(tài),在使用應(yīng)用程序的過(guò)程中仍然會(huì)產(chǎn)生可變的部分。在這種情況下,配置管理工具