軟件測(cè)試 | 確保部署流程是冪等的(Idempotent)
無(wú)論開(kāi)始部署時(shí)目標(biāo)環(huán)境處于何種狀態(tài),部署流程應(yīng)該總是令目標(biāo)環(huán)境達(dá)到同樣(正確)的狀態(tài),并以之為結(jié)束點(diǎn)。
做到這一點(diǎn)的最簡(jiǎn)單方法就是,將已知狀態(tài)良好的基線環(huán)境作為起點(diǎn),要么是通過(guò)自動(dòng)化,要么是通過(guò)虛擬化方式準(zhǔn)備好的。這里所說(shuō)的環(huán)境包括所有需要用到的中間件
,以及讓?xiě)?yīng)用程序能正常工作的任何軟硬件。然后,部署流程可以獲取指定的應(yīng)用程序版本,并使用(對(duì)于中間件來(lái)說(shuō))適當(dāng)?shù)牟渴鸸ぞ邔⑵洳渴鸬皆摥h(huán)境中。
如果你的配置管理做的不夠好,還無(wú)法滿足這一要求的話,下一步最好把部署流程對(duì)該環(huán)境作出的那些前提假設(shè)驗(yàn)一遍。如果這些假設(shè)不成立,就讓部署失敗。比如你要驗(yàn)證一下適當(dāng)?shù)闹虚g件是否已經(jīng)安裝了,是否正在運(yùn)行,是否為正確的版本。而且,無(wú)論如何,你都要驗(yàn)證一下該應(yīng)用程序所依賴的外部服務(wù)是否也在運(yùn)行并且為正確的版本。
如果應(yīng)用程序通過(guò)了測(cè)試、構(gòu)建,并已集成為一個(gè)整體的話,通常應(yīng)該以部署單件的方式來(lái)部署它。也就是說(shuō),每次部署時(shí)都應(yīng)該基于根據(jù)版本庫(kù)中的某個(gè)單一修正版本生成的二進(jìn)制包從頭開(kāi)始。對(duì)多層系統(tǒng)也是一樣,比如同時(shí)開(kāi)發(fā)了應(yīng)用程序的表現(xiàn)層和應(yīng)用層。那么當(dāng)部署其中的某層組件時(shí),就應(yīng)該將任意一層上的組件都部署一次。
為了將變更最小化,很多組織堅(jiān)持只部署那些發(fā)生過(guò)修改的組件。然而,我們很難回答“哪些東西發(fā)生了變更”這個(gè)問(wèn)題,而且這一判斷過(guò)程比從頭開(kāi)始部署更容易出錯(cuò),也很難測(cè)試。當(dāng)然,所有可能的變更組合是不可能的,所以如果某個(gè)沒(méi)有想到的無(wú)法控制的情況恰恰在發(fā)布時(shí)發(fā)生了,就會(huì)使應(yīng)用程序處于某種未知狀態(tài)。
對(duì)于這一原則,也有一些例外情況。首先,對(duì)于集群系統(tǒng)來(lái)說(shuō),總是將整個(gè)集群系統(tǒng)同時(shí)重新部署就不可取。
其次,如果應(yīng)用程序是由多個(gè)組件構(gòu)成的,而這些組件來(lái)源于不同的源代碼庫(kù),那么二進(jìn)制包就由這些源代碼庫(kù)中的一系列修正版本(x、y、z.....)來(lái)定義。此時(shí),如果你知道僅有一個(gè)組件發(fā)生了變更,而且將要部署到生產(chǎn)環(huán)境的所有組件的組合都已經(jīng)測(cè)試通過(guò)了的話,那么只部署這個(gè)發(fā)生變更的組價(jià)就行了。這里的關(guān)鍵區(qū)別在于從上一個(gè)狀態(tài)更新到新?tīng)顟B(tài)的過(guò)程已被測(cè)試過(guò)。這一原則也適用于面向服務(wù)架構(gòu)的服務(wù)部署上。
最后,還有一種方法,那就是使用效果冪等的工具進(jìn)行部署。比如,無(wú)論目標(biāo)目錄中的文件處于什么狀態(tài),Rsync都會(huì)使用一種強(qiáng)大的算法,僅通過(guò)網(wǎng)絡(luò)傳輸目標(biāo)目錄與源目錄中不同的部分,確保某系統(tǒng)上的目標(biāo)目錄與另一個(gè)系統(tǒng)中的源目錄是完全一樣的。版本控制的目錄更新也能達(dá)到相似的結(jié)果。