在部署的方式的第一部分我們介紹了基礎(chǔ)設(shè)施即代碼的概念杏糙、原則和工具玫芦,那么現(xiàn)在我們就來(lái)看看應(yīng)用部署的方式有哪些浆熔。
In Place Deployment(直接替換部署)
如果你的應(yīng)用服務(wù)器數(shù)量很少,比如只有一臺(tái)桥帆,那么最簡(jiǎn)單的方式就是通過(guò)在原來(lái)的服務(wù)器上直接更新應(yīng)用医增。當(dāng)然,最好是通過(guò)使用前面所介紹的基礎(chǔ)設(shè)施即代碼的工具來(lái)完成老虫。
在部署的時(shí)候叶骨,最好提前自動(dòng)將loadbalancer指向一個(gè)維護(hù)的頁(yè)面,并且donwtime所有監(jiān)控的服務(wù)祈匙,比如Nagios忽刽,Zabbix等天揖,如果它們發(fā)出警報(bào),那么on-call的人就不知道這是在部署還是生產(chǎn)環(huán)境真的出了問(wèn)題跪帝。
- 如果部署成功今膊,測(cè)試無(wú)誤,再將loadbalancer指向應(yīng)用服務(wù)器伞剑,undowntime監(jiān)控服務(wù)
- 如果部署成功斑唬,測(cè)試出現(xiàn)問(wèn)題,如果使用包管理工具進(jìn)行部署黎泣,那么可以用這些工具來(lái)revert恕刘,比如
yum downgrade app
,如果用了其它自動(dòng)化配置管理工具比如ansible抒倚,那么好的實(shí)踐是revert更新的那次配置的提交褐着,重新運(yùn)行自動(dòng)化配置管理的流程(如持續(xù)交付/集成流水線),來(lái)回滾衡便。不要在服務(wù)器上做任何的手動(dòng)操作献起。回滾后將loadbalancer指向服務(wù)器镣陕,同時(shí)undowntime監(jiān)控服務(wù)谴餐。 - 如果部署失敗,同2呆抑,回滾配置岂嗓,通過(guò)部署流水線來(lái)回滾應(yīng)用版本,enable loadbalancer鹊碍,同時(shí)undowntime監(jiān)控服務(wù)厌殉。
這種方式不好的地方在于需要停止服務(wù)部署,不過(guò)看上去很多國(guó)內(nèi)的互聯(lián)網(wǎng)公司都還是在使用這種方式侈咕,從正在維護(hù)的頁(yè)面(排除嗶因素外)公罕,當(dāng)然這只是不負(fù)責(zé)任的猜測(cè)。
Rolling Update Deployment(滾動(dòng)更新部署)
當(dāng)你的應(yīng)用有多臺(tái)服務(wù)器時(shí)耀销,你可以考慮通過(guò)滾動(dòng)更新的方式楼眷,也就是逐臺(tái)或者批量(每幾臺(tái)服務(wù)器)更新的方式。比如像下面這樣:
步驟如下:
- 自動(dòng)化部署的工具通知loadbalancer讓它disable其中一臺(tái)或者幾臺(tái)服務(wù)器(得保證有足夠數(shù)量的服務(wù)器在線并能滿足當(dāng)前的請(qǐng)求)
- 同樣熊尉,downtime監(jiān)控服務(wù)罐柳,通過(guò)自動(dòng)化配置工具等更新服務(wù),部署成功狰住,測(cè)試完成后张吉,loadbalancer enable已更新的服務(wù)器,undowntime監(jiān)控服務(wù)
- 重復(fù)2的步驟催植,直至所有服務(wù)器都更新完成
- 如果全部更新完成才發(fā)現(xiàn)問(wèn)題肮蛹,取決于問(wèn)題的嚴(yán)重程度勺择,很嚴(yán)重可以將loadbalancer指向維護(hù)頁(yè)面,然后revert自動(dòng)化配置工具的修改蔗崎,同時(shí)更新全部服務(wù)器酵幕,如果不是很嚴(yán)重但是需要回退版本,可以revert配置缓苛,然后以滾動(dòng)更新的方式再部署一遍
- 如果在部署的過(guò)程中某臺(tái)服務(wù)器失敗芳撒,根據(jù)具體的原因,采取修復(fù)或者回退的策略
這種方式的好處就是可以保證服務(wù)一直在線(0 downtime),但是不好的地方在于未桥,線上同時(shí)存在了兩個(gè)不同的版本笔刹,同時(shí),因?yàn)槭菍?duì)已存在的服務(wù)器的更新冬耿,所以出現(xiàn)第一部分所提到的服務(wù)器侵蝕時(shí)舌菜,很容易導(dǎo)致部署的失敗。
Immutable Deployment(不可變部署)
即便是在沒(méi)有人工干預(yù)的情況下亦镶,服務(wù)器也會(huì)因?yàn)槿缛罩緦?xiě)滿磁盤卻沒(méi)有定期rotate導(dǎo)致服務(wù)器部署出錯(cuò)日月,這樣的服務(wù)器我們可以成為可變基礎(chǔ)設(shè)施(Mutable infrastructure),也就是說(shuō)這個(gè)服務(wù)器本身是會(huì)變化或者被修改的缤骨。怎么理解這個(gè)問(wèn)題呢爱咬,我們以Scala來(lái)舉例。Scala中有通過(guò)val
定義的不可變變量绊起,也有通過(guò)var
定義的可變變量精拟。當(dāng)你創(chuàng)建一個(gè)val
變量時(shí),你沒(méi)有辦法對(duì)它做任何修改虱歪,如果想更改它的值只能通過(guò)新建另一個(gè)val
變量蜂绎,但是在用var
聲明的時(shí)候,它的值就是可變的笋鄙,你完全無(wú)法預(yù)期它會(huì)被賦上什么值师枣。當(dāng)然,我們通過(guò)代碼在命令行里面去修改萧落,這個(gè)變化可見(jiàn)坛吁、可控,但是應(yīng)用在服務(wù)器上運(yùn)行铐尚,它變化成什么無(wú)法預(yù)測(cè)的,你怎么知道它不會(huì)從國(guó)際主義者變成狹隘的民族主義者哆姻。
scala> val immutable = 2
immutable: Int = 2
scala> immutable =3
<console>:8: error: reassignment to val
immutable =3
^
scala> var mutable = 3
mutable: Int = 3
scala> mutable = 4
mutable: Int = 4
所以最好的辦法就是每次部署都從頭開(kāi)始宣增,重新創(chuàng)建服務(wù)器,安裝新版本的服務(wù)以及應(yīng)用對(duì)應(yīng)的新配置矛缨。測(cè)試完成后爹脾,如果沒(méi)有問(wèn)題帖旨,將loadbalancer指向新的服務(wù)器集群,同時(shí)干掉舊的服務(wù)器集群灵妨。
支持這樣的部署方式解阅,需要你的虛擬化解決方案(通過(guò)命令行或者API的方式)的支持。以我們的基礎(chǔ)設(shè)施為例泌霍,在自建的數(shù)據(jù)中心中采用了VMware的虛擬化解決方案货抄,支持通過(guò)API的方式動(dòng)態(tài)創(chuàng)建、銷毀服務(wù)器朱转,Loadbalancer使用NetScaler蟹地,也提供了SOAP API去動(dòng)態(tài)更改配置,同理藤为,監(jiān)控使用Nagios也支持怪与。那么很容易就可以實(shí)現(xiàn)一個(gè)這樣的自動(dòng)化部署工具,每次在部署時(shí)重新生成服務(wù)器缅疟,安裝部署應(yīng)用分别,然后干掉舊的服務(wù)器。好的云平臺(tái)存淫,比如AWS耘斩,它提供的Cloudformation工具,內(nèi)建了這種不可變部署的功能纫雁,使用起來(lái)更加的簡(jiǎn)單煌往。
從不可變的部署,我們可以引出另一個(gè)概念轧邪,不可變基礎(chǔ)設(shè)施(immutable infrastructure).不可變基礎(chǔ)設(shè)施是一種在IT資源上管理服務(wù)和軟件部署的方法刽脖,其中組件被替換而不是更改,每次的變更通過(guò)這種替換的方式有效地重新部署應(yīng)用程序或服務(wù)忌愚。其主要目的是為了解決可變基礎(chǔ)設(shè)施的下列問(wèn)題:
- 當(dāng)你的業(yè)務(wù)發(fā)展曲管,或者是微服務(wù)拆分時(shí)導(dǎo)致服務(wù)、服務(wù)器數(shù)量增加時(shí)硕糊,基礎(chǔ)設(shè)施的維護(hù)成本也倍增院水。
- 可變基礎(chǔ)設(shè)施上部署更容易出錯(cuò)。如我們?cè)诘谝徊糠炙榻B的雪花服務(wù)器简十,配置漂移等都會(huì)導(dǎo)致未知的部署錯(cuò)誤檬某。
- 鑒別錯(cuò)誤、分析威脅的成本很高螟蝙。比如操作系統(tǒng)恢恼、基礎(chǔ)軟件經(jīng)常會(huì)出現(xiàn)一些漏洞,需要給服務(wù)器打補(bǔ)丁胰默,去查找那些服務(wù)器需要打補(bǔ)丁要耗費(fèi)很多時(shí)間场斑,雖然你可以安裝類似Security Center這樣的工具幫你分析大漓踢,但是這給帶來(lái)了額外的成本開(kāi)銷。還有因?yàn)檠┗ǚ?wù)器或者服務(wù)器侵蝕導(dǎo)致的問(wèn)題漏隐,定位問(wèn)題的時(shí)間開(kāi)銷也很大喧半。
- 如果我們?cè)谠破脚_(tái)上也做類似的事情,如果服務(wù)器需要補(bǔ)丁青责,很有可能會(huì)被平臺(tái)主動(dòng)patch挺据,重啟服務(wù)。
而我們采用不可變基礎(chǔ)設(shè)施爽柒,可以簡(jiǎn)化維護(hù)的過(guò)程吴菠,部署也會(huì)更加簡(jiǎn)單,成功率更高浩村,如果你保持每天部署做葵,很多威脅、補(bǔ)丁都在基礎(chǔ)鏡像中更新過(guò)了心墅,也避免了分析威脅錯(cuò)誤的成本酿矢。如果你采用了云計(jì)算平臺(tái)或者你的基礎(chǔ)設(shè)施支持這種方式,那么最好采用這種不可變部署方式去更新應(yīng)用或者服務(wù)怎燥。
Red-Black Deployment(紅黑部署)
這是Netflix采用的部署手段瘫筐,Netflix的主要基礎(chǔ)設(shè)施是在AWS上,所以它利用AWS的特性铐姚,在部署新的版本時(shí)策肝,通過(guò)AutoScaling Group用包含新版本應(yīng)用的AMI的LaunchConfiguration創(chuàng)建新的服務(wù)器。測(cè)試不同過(guò)隐绵,找到問(wèn)題原因后之众,直接干掉新生成的服務(wù)器以及Autoscaling Group就可以,測(cè)試通過(guò)依许,則將ELB指向新的服務(wù)器集群棺禾,然后銷毀掉舊的服務(wù)器集群以及AutoScaling Group。
紅黑部署的好處是服務(wù)始終在線峭跳,同時(shí)采用不可變部署的方式膘婶,也不像藍(lán)綠部署一樣得保持冗余的服務(wù)始終在線。
AWS的Cloudformation內(nèi)建了對(duì)紅黑部署的支持蛀醉,比如我的這個(gè)例子里面的配置項(xiàng):
autoScalingGroup:
CreationPolicy:
ResourceSignal:
Count: 1
Timeout: PT10M
AutoScalingCreationPolicy:
MinSuccessfulInstancesPercent: 100
UpdatePolicy:
AutoScalingScheduledAction:
IgnoreUnmodifiedGroupSizeProperties: false
AutoScalingReplacingUpdate:
WillReplace: true
這是我的應(yīng)用的AutoScaling Group的配置項(xiàng)悬襟,其中AutoScalingReplacingUpdate
的配置項(xiàng)中的WillReplace
為true時(shí),在LaunchConfiguration有任何變動(dòng)時(shí)拯刁,比如我修改了user-data
中運(yùn)行容器的版本號(hào)古胆,在我更新Cloudformation時(shí),它會(huì)自動(dòng)創(chuàng)建新的服務(wù)器,并且在服務(wù)器通過(guò)ELB的health-check后逸绎,將ELB指向新的服務(wù)器,然后干掉舊的服務(wù)器夭谤,如此則完成了一次0 downtime的不可變部署棺牧。
Blue-Green Deployment(藍(lán)綠部署)
藍(lán)綠部署是最常見(jiàn)的一種0 downtime部署的方式,原理上很簡(jiǎn)單朗儒,就是通過(guò)冗余來(lái)解決問(wèn)題颊乘。通常在Loadbalancer上你需要兩組配置,一組是active的生產(chǎn)環(huán)境的配置醉锄,一組是inactive的配置(也算是生產(chǎn)環(huán)境)乏悄,用戶來(lái)訪問(wèn)的時(shí)候,Loadbalancer只會(huì)讓他訪問(wèn)active的服務(wù)器集群恳不,但是inactive的環(huán)境是可訪問(wèn)的檩小。這個(gè)時(shí)候如果你需要部署,只要針對(duì)inactive環(huán)境烟勋,更新所有的服務(wù)器即可规求,然后Loadbalancer切換下active或者inactive指向服務(wù)器集群即可。這種方式的好處在你可以始終很放心的去部署inactive環(huán)境卵惦,如果出錯(cuò)并不影響生產(chǎn)環(huán)境的服務(wù)阻肿,如果切換后出現(xiàn)問(wèn)題,也可以在非常短的時(shí)間內(nèi)把再做一次切換沮尿,就完成了回滾丛塌。而且同時(shí)在線的只有一個(gè)版本。這種方式不好的地方在于冗余產(chǎn)生的額外維護(hù)畜疾、配置的成本赴邻,以及服務(wù)器本身運(yùn)行的開(kāi)銷。
我們?cè)谧越ǖ臄?shù)據(jù)中心里面就采用藍(lán)綠部署庸疾,同時(shí)是不可變的部署方式乍楚。因?yàn)槭〉某杀竞艿停援?dāng)自動(dòng)化流水線搭建起來(lái)時(shí)届慈,任何人都可以去做部署徒溪。
我在這里用haproxy模擬了一個(gè)藍(lán)綠部署的例子,有興趣的可以看下金顿。
Multi Region Deployment(多區(qū)域部署) or DR As Deployment(災(zāi)備即部署)
如果你的服務(wù)需要給不同的地區(qū)使用臊泌,為了提高使用體驗(yàn),你的應(yīng)用或者服務(wù)會(huì)部署到盡量靠近用戶的位置揍拆,所以會(huì)出現(xiàn)數(shù)據(jù)中心處于不同的region(區(qū)域)的情況渠概,比如大陸和北美。這種方式同時(shí)是一種災(zāi)備的考量,如果其中一個(gè)區(qū)域的數(shù)據(jù)中心停電播揪,那么還有另外一個(gè)數(shù)據(jù)中心可以提供服務(wù)贮喧,保證業(yè)務(wù)的可用性。想要讓多個(gè)區(qū)域的服務(wù)做到0 downtime部署猪狈,就得采取類似藍(lán)綠部署的策略箱沦,但是不同的地方在于藍(lán)綠部署是active-inactive模式,而多區(qū)域的部署是active-active模式雇庙。
我舉一個(gè)我們做多區(qū)域部署的例子谓形。我們主站的基礎(chǔ)設(shè)施最前面是Akamai,它分別將60%和40%的流量loadbalancer到兩個(gè)不同區(qū)域的數(shù)據(jù)中心疆前,每個(gè)數(shù)據(jù)中心中最前面是NetScaler做Loadbalancer寒跳,將請(qǐng)求分發(fā)給25臺(tái)主站的服務(wù)器。每臺(tái)服務(wù)器上運(yùn)行的Java應(yīng)用都會(huì)運(yùn)行newrelic的agent將服務(wù)的數(shù)據(jù)傳給Newrelic服務(wù)器竹椒。Akamai通過(guò)心跳檢測(cè)來(lái)確定數(shù)據(jù)中心是否在線童太。
- 在開(kāi)始部署的時(shí)候,首先通過(guò)自動(dòng)化部署流水線碾牌,讓NetScaler禁止Akamai訪問(wèn)其中一個(gè)數(shù)據(jù)中心A康愤,那么Akamai就認(rèn)為這個(gè)數(shù)據(jù)中心宕機(jī)了,然后會(huì)把100%流量都指向另一個(gè)數(shù)據(jù)中心B
- 自動(dòng)化腳本會(huì)檢查Newrelic中A數(shù)據(jù)中心的RPM(Request Per Minute)舶吗,如果這個(gè)數(shù)值降到1000一下征冷,那么我們可以認(rèn)為幾乎沒(méi)有任何外部的服務(wù)訪問(wèn)這個(gè)數(shù)據(jù)中心,就可以放心的觸發(fā)下一個(gè)build job去自動(dòng)化部署數(shù)據(jù)中心B中所有應(yīng)用誓琼,這里需要通過(guò)批量滾動(dòng)部署的方式检激,以保證數(shù)據(jù)中心內(nèi)部訪問(wèn)這個(gè)服務(wù)不出問(wèn)題。
- 完成部署腹侣、測(cè)試后叔收。再通過(guò)自動(dòng)化腳本讓Akamai心跳檢測(cè)可以訪問(wèn)到A數(shù)據(jù)中心,然后不讓它訪問(wèn)B數(shù)據(jù)中心傲隶。同理饺律,等到數(shù)據(jù)中心B中服務(wù)的訪問(wèn)RPM降低到安全數(shù)值時(shí),做相同的事情跺株。
- B中所有服務(wù)更新測(cè)試完成后复濒,通過(guò)自動(dòng)化腳本讓Akamai的心跳檢測(cè)可以訪問(wèn)到兩個(gè)數(shù)據(jù)中心,然后流量會(huì)自動(dòng)的切換到60%/40%乒省。
這樣的部署相對(duì)比較安全巧颈,服務(wù)始終在線而且出錯(cuò)的回滾也比較容易。不太好的地方就是稍微有點(diǎn)耗時(shí)袖扛,如果對(duì)整個(gè)部署的過(guò)程做簡(jiǎn)單優(yōu)化的話砸泛,部署的時(shí)間大概會(huì)在一個(gè)小時(shí)左右。所以部署的時(shí)間成本會(huì)比較高。
如果你使用云平臺(tái)唇礁,比如AWS勾栗、Azure,可以通過(guò)它們的DNS服務(wù)來(lái)做到相同的事情垒迂,比如你可以告訴AWS的R53械姻,讓它主動(dòng)的將服務(wù)failover到其中一個(gè)region。
我所知道的自動(dòng)化部署的方式大概就是這些机断,下一節(jié)我會(huì)分享使用基于12factors原則針對(duì)docker部署的經(jīng)驗(yàn)。