隨著Docker容器的興起,云原生應用越來越流行。事實上,云原生應用的設(shè)計理念和原則,在Docker產(chǎn)生之前就已經(jīng)被軟件架構(gòu)大師們提出來,只不過在容器出現(xiàn)之前,以虛擬機鏡像為基礎(chǔ)的應用打包發(fā)布方式開銷過大,普通開發(fā)人員較少使用,流行不起來。以云原生應用的核心設(shè)計原則12要素來看,我們可以發(fā)現(xiàn)Docker正是在設(shè)計中融入了對云原生應用的深層支持,才得以風靡軟件的世界。隨著對12要素的理解加深,我們也同時會發(fā)現(xiàn)12要素之間的彼此聯(lián)系緊密,是圍繞一個核心目標的12項具體指導原則。而這個核心目標就是提高應用的可移植性和移動性。
X Docker對12要素的支持
基準代碼
應用有一套基準代碼,可以部署到多種環(huán)境中。這樣可以保證同一套代碼容易遷移到不同環(huán)境中去運行。
在Docker的體系中,Dockerfile與也是基準代碼的一部分,跟應用業(yè)務代碼保存在同一個代碼倉庫中,用同一套版本標號。基于Docker體系交付的軟件產(chǎn)品不再是一個可執(zhí)行程序,而是一個Docker鏡像。Docker鏡像的移動性比傳統(tǒng)的可執(zhí)行程序高得多。
依賴
應用要清楚地聲明和隔離自己依賴的程序庫。這樣才能保證應用移動到其他環(huán)境時,自己所依賴的程序庫也正常運行,并且與環(huán)境中其他軟件不互相干擾。
Docker通過Dockerfile中的命令將自己依賴的程序聲明出來,并通過dockerbuild命令將這些依賴的程序庫打包到交付的Docker鏡像中。
配置
運行時配置要存儲到運行時環(huán)境中。一個應用的行為邏輯受兩方面因素控制,一方面因素是代碼,另一方面因素是配置;代碼是與運行時環(huán)境無關(guān)的,要保存在應用開發(fā)的代碼倉庫中,而配置是與運行時環(huán)境相關(guān)的。將配置存儲到運行時環(huán)境中保證了配置與環(huán)境的一致性。
Docker在Dockerfile中用ENV命令聲明自己運行時所依賴的環(huán)境
變量和環(huán)境變量的默認值,在docker run命令的--env參數(shù)可以在運行時設(shè)定環(huán)境變量的值。
后端支撐服務
將數(shù)據(jù)庫、緩存、消息隊列服務這些后臺支撐服務當作可掛載的資源。保證這些后端支撐服務對應用業(yè)務完全透明,應用只是把這些服務當作一種透明的資源來使用,這樣更換環(huán)境部署應用只需要更改與資源相關(guān)的環(huán)境變量。
在Docker體系中,通行的做法正是將數(shù)據(jù)庫、緩存和消息隊列等后臺支撐服務當作資源在Docker容器運行時掛載。而應用程序在構(gòu)建鏡像時,需要將所需要的資源的環(huán)境變量用ENV聲明出來,在容器運行時,實際環(huán)境中的資源環(huán)境變量則以--env參數(shù)的方式設(shè)置到容器中。
構(gòu)建發(fā)布運行
嚴格區(qū)分構(gòu)建和運行這兩個不同的階段。通過清楚地區(qū)分構(gòu)建期和運行期兩個階段,對應的軟件控制因素也清楚地分為代碼和配置兩類;代碼在構(gòu)建完成后是不會改變的,而且一套代碼可以自由地部署到多套環(huán)境中去運行,不同環(huán)境中應用軟件運行所需要改變的僅僅是配置。
在Docker體系中,構(gòu)建器的“代碼”不僅僅是應用程序編程語言的代碼(例如Java,C,Python等),也包括這些代碼運行時所固定依賴的程序庫和這些程序庫的“靜態(tài)配置”。稱其為“靜態(tài)配置”主要是指這些配置不會因為部署環(huán)境的改變而改變,因此這些“靜態(tài)配置”實際上成為的Docker鏡像的“代碼”。因此,對Docker鏡像來說,應用業(yè)務代碼和靜態(tài)配置都是“代碼”;只有根據(jù)部署環(huán)境可能變動的“動態(tài)配置”,才是真正的“配置”,而這些配置對應了Docker運行時的環(huán)境變量。
進程
將應用作為無狀態(tài)的進程來運行。無狀態(tài)進程保證應用可以隨時啟動和關(guān)閉,隨時根據(jù)業(yè)務壓力而增加或減少運行實例數(shù),保證應用的移動性。
由于Docker容器技術(shù)相對于虛擬機技術(shù)來說,大大降低了運行應用實例的開銷,提高了啟動和關(guān)閉應用實例的速度,應用Docker體系發(fā)布的應用與無狀態(tài)應用的模型更加匹配。
端口綁定
通過端口綁定來發(fā)布服務。保證一個應用服務在不同的運行環(huán)境中,可以用指定的任何端口來發(fā)布,這也是提高應用移動性的一個重要原則。
Docker在Dockerfile中用EXPOSE命令聲明自己運行時容器所要發(fā)布的端口,在dockerrun命令的-p參數(shù)可以指定主機上發(fā)布服務的端口與容器端口的映射,這樣的設(shè)計幫助應用開發(fā)者自然而然的實現(xiàn)云原生應用對端口綁定的要求:內(nèi)部的端口在構(gòu)建期決定,而對外發(fā)布的實際端口在在運行環(huán)境中決定。
并發(fā)
可以通過水平伸縮應用的進程數(shù)來增大或縮小系統(tǒng)的容量。
如前所述,Docker容器的設(shè)計保證了水平伸縮的高效率。
可丟棄性
應用進程可以快速啟動也可以優(yōu)雅地關(guān)閉。
Docker容器在快速啟動和優(yōu)雅關(guān)閉方面的效率要大大高于傳統(tǒng)虛擬機,使得結(jié)合Docker容器實現(xiàn)應用的可丟棄性成為自然而然的事情。
開發(fā)生產(chǎn)對等
保持開發(fā)環(huán)境、測試環(huán)境、預發(fā)布環(huán)境和生產(chǎn)環(huán)境盡量一致。保持各種環(huán)境一致,才能減少因為環(huán)境不一致造成的與業(yè)務代碼無關(guān)的錯誤,提高應用的可移動性。
Docker容器流行起來的一大原因,就是它將應用程序所依賴的程序庫以及這些程序庫的“靜態(tài)配置”一并打包成Docker鏡像,以Docker鏡像部署到不同的環(huán)境中,從而大大減少了不同環(huán)境上應用的差別,保證了一次構(gòu)建,任何地方部署運行。
日志
將日志以帶時間戳的事件流方式來管理。把日志當作事件流來管理,實際是將日志作為結(jié)構(gòu)化的數(shù)據(jù)而不是非結(jié)構(gòu)化的文件來管理,這樣使得日志方便在云環(huán)境中由云平臺統(tǒng)一管理和分析;否則,在云環(huán)境中分布在各處各自為政的日志將給系統(tǒng)分析和排錯打來極大困難。
Docker正是將日志以事件來管理的。利用dockerlogs命令可以查詢指定容器的日志,同時,所有容器的日志正是以結(jié)構(gòu)化JSON數(shù)據(jù)的格式默認保存在/var/lib/docker/containers//目錄中。云平臺管理軟件可以統(tǒng)一管理處理相應的日志文件給用戶提供方便的差錯工具。
管理進程
將管理任務當作一次性任務來運行。這樣保證所有的管理任務都是可以在云平臺環(huán)境下自動化的,從而為大規(guī)模應用的自動運維,大幅度的自動伸縮提供了基礎(chǔ)。
在Docker體系下,所有的管理工作都有相應的docker客戶端命令和docker的RESTAPI服務提供支持,使得云平臺可以通過調(diào)用命令行或REST API來管理容器。
Docker對云原生應用的構(gòu)建和小規(guī)模測試有很好的支持,但是對于管理跨主機、大規(guī)模的云原生應用環(huán)境,Kubernetes則更為功能強大,我將在后文予以介紹。
參考:
http://