《持續交付:發布可靠軟體的系統方法》第2章 配置管理
- 2019 年 10 月 8 日
- 筆記
第 2 章 配置管理
2.1 引言
- 配置管理是指一個過程,通過該過程,所有與項目相關的產物,以及它們之間的關係都被唯一定義、修改、存儲和檢索
- 配置管理策略將決定如何管理項目中發生的一切變化。它記錄了你的系統以及應用程式的演進過程。另外,它也是對團隊成員協作方式的管理
2.2 使用版本控制
- 版本控制系統的目的有兩個
- 它要保留每個文件的所有版本的歷史資訊,並使之易於查找
- 它讓分散式團隊(無論是空間上不在一起,還是不同的時區)可以愉快地協作
2.2.1 對所有內容進行版本控制
- 每個與所開發的軟體相關的產物都應被置於版本控制之下。開發人員不但要用它來管理和控制源程式碼,還要把測試程式碼、資料庫腳本、構建和部署腳本、文檔、庫文件和應用軟體所用的配置文件都納入到版本控制之中,甚至把編譯器以及工具集等也放在裡面,以便讓新加入項目的成員可以很容易地從零開始工作
- 我們無論怎麼強調「做好配置管理」都不算過分。我們所討論的有關加快發布周期和提高軟體品質的所有實踐,從持續集成、自動化測試,到一鍵式部署,都依賴於下面這個前提:與項目相關的所有東西都在版本控制庫中
2.2.2 頻繁提交程式碼到主幹
- 使用版本控制時,有兩點需要牢記在心
- 首先,只有頻繁提交程式碼,你才能享受版本控制所帶來的眾多好處,比如能夠輕鬆地回滾到最近某個無錯誤的版本
- 其次,一旦將變更提交到版本控制中,那麼團隊的所有人都能看到這些變更,也能簽出它。而且,如果使用了持續集成(像我們推薦的那樣),你所做的修改還會觸發一次構建,本次構建很有可能會最終進入驗收測試,甚至被部署到生產環境
- 有些人解決這個兩難問題的方法是,在版本控制系統中為新功能建立單獨的分支。到某個時間點後,如果這些修改的品質令人滿意,就將其合併到主幹。我們對這樣的做法持反對意見
- 它違背了持續集成的宗旨,因為創建分支的做法推遲了新功能的整合,只有當該分支被合併時才可能發現集成問題
- 如果多個開發者同時分別創建了多個分支,問題會成指數增加,而合併過程也會極其複雜
- 儘管有一些好用的工具有自動合併功能,但它們無法解決語義衝突
- 它讓重構程式碼庫變得非常困難,因為分支往往涉及多個文件,會讓合併變得更加困難
- 一個更好的解決方案是盡量使用增量方式開發新功能,並頻繁且有規律地向版本控制系統提交程式碼。這會讓軟體能一直保持在集成以後的可工作狀態。你的軟體會一直被測試,因為每次提交程式碼時,持續集成伺服器就會從程式碼主幹上運行自動測試。這會減小因重構引起的大規模合併導致衝突的可能性,
- 為了確保提交程式碼時不破壞已有的應用程式,有兩個實踐非常有效
- 在提交程式碼之前運行測試套件。這個測試套件應該是一個快速運轉(一般少於10分鐘)且相對比較全面的測試集合,
- 增量式引入變化。我們建議每完成一個小功能或一次重構之後就提交程式碼
2.2.3 使用意義明顯的提交注釋
- 我們喜歡的一種注釋風格是這樣的:第一段是簡短的總結性描述,接下來的幾段描述更多的細節
- 這個注釋中還應該包括一個鏈接,可以鏈接到項目管理工具中的一個功能或缺陷,從而知道為什麼要修改這段程式碼
2.3 依賴管理
2.3.1 外部庫文件管理
- 我們建議在本地保存一份外部庫的副本(如果使用Maven,應該創建一個本地倉庫,裡面存放那些在你的公司中統一使用的外部庫)。這樣,你就總能再現構建過程
2.3.2 組件管理
- 將整個應用軟體分成一系列的組件進行開發(小型應用除外)是個不錯的實踐。這能讓某些變更的影響範圍比較小,從而減少回歸缺陷。另外,它還有利於重用,使大項目的開發過程更加高效
2.4 軟體配置管理
- 應該以對待程式碼的方式來對待你的系統配置,使其受到正確的管理和測試
2.4.1 配置與靈活性
- 更好的方法幾乎總是先專註於提供具有高價值且可配置程度較低的功能,然後在真正需要時再添加可配置選項
2.4.2 配置的分類
- 我們可以在構建、部署、測試和發布過程中的任何一點進行配置資訊的設置。而且,我們也的確會在多個時間點對應用軟體進行相關的配置
- 在生成二進位文件時,構建腳本可以在構建時引入相關的配置
- 在打包時將配置資訊一同打包到軟體中
- 在安裝部署軟體程式時,部署腳本或安裝程式可以獲取必要的配置資訊,或者直接要求用戶輸入這些配置資訊
- 軟體在啟動或運行時可獲取配置
- 一般來說,我們並不贊同在構建或打包時就將配置資訊植入的做法
2.4.3 應用程式的配置管理
- 在管理應用程式的配置這個問題上,需要回答三個問題
- (1) 如何描述配置資訊?
- (2) 部署腳本如何存取這些配置資訊?
- (3) 在環境、應用程式,以及應用程式各版本之間,每個配置資訊有什麼不同?
- 通常配置資訊以鍵值對的形式來表示。1有時可使用系統提供的配置類型來有層次地組織這些配置項
- 版本控制庫可能是最容易的,只要將配置文件簽入就可以了,而且你可以隨時拿到任意時間點上的歷史配置資訊
獲取配置資訊
- 管理配置最有效的方法是讓所有的應用程式通過一個中央服務系統得到它們所需要的配置資訊
為配置項建模
- 無論你使用哪種方式來存儲配置資訊,放在源程式碼控制中的XML文件也好,或REST式Web服務中也好,都要能夠滿足不同的要求
- 新增一個環境(比如一個新的開發工作站,或性能測試環境)。在這種情況下你要能為這個配置應用的新環境指定一套新的配置資訊
- 創建應用程式的一個新版本,通常需要添加一些配置設置,刪除一些過時的配置設置。此時應該確保在部署新版本時,可以使用新的配置設置,但是一旦需要回滾時,還能夠使用舊版本的配置設置
- 將新版本從一個環境遷移到另一個環境,此時應該確保新環境上的新配置項都有效,而且為其設置了正確的值
- 重定向到一個資料庫伺服器。應該只需要簡單地修改所有配置設置,就能讓它指向新的資料庫伺服器
- 通過虛擬化技術管理環境。應該能夠使用虛擬技術管理工具創建某種指定的環境,並且配置好所有的虛擬機
- 在不同環境之間管理配置資訊的一種方法是,把預期的生產環境中的配置資訊作為默認配置,而在其他環境中,通過適當的方式覆蓋這些默認值(確保你有預防措施,以防生產環境受到配置失誤的影響)
系統配置的測試
- 一是要保證配置設置中對外部服務的引用是良好的。最起碼,要保證能夠與所有的外部服務相連通
- 二是當應用程式一旦安裝好,就要在其上運行一些冒煙測試,以驗證它運行正常
2.4.4 跨應用的配置管理
- 在大中型組織中,通常會同時管理很多應用程式,最重要的任務之一就是,要為每個應用程式維護一份所有配置選項的索引表,記錄這些配置保存在什麼地方,它們的生命周期是多長,以及如何修改它們
- 如果可能的話,運行每個應用程式的構建腳本時應該自動生成一份這類資訊。即使無法做到這一點,也要把它記錄在Wiki上,或其他文檔管理系統中
- 每個應用程式的配置項管理都應該作為項目啟動階段的一個議題,納入計劃當中
2.4.5 管理配置資訊的原則
- 我們要把應用程式的配置資訊當做程式碼一樣看待,恰當地管理它,並對它進行測試。應該考慮以下幾個方面
- 在應用程式的生命周期中,我們應該在什麼時候注入哪類配置資訊
- 將應用程式的配置項與源程式碼保存在同一個存儲庫中,但要把配置項的值保存在別處
- 應該總是通過自動化的過程將配置項從保存配置資訊的存儲庫中取出並設置好,這樣就能很容易地掌握不同環境中的配置資訊了
- 配置系統應該能依據應用、應用軟體的版本、將要部署的環境,為打包、安裝以及部署腳本提供不同的配置值。每個人都應該能夠非常容易地看到當前軟體的某個特定版本部署到各種環境上的具體配置資訊
- 確保配置資訊是模組化且封閉的,使得對某處配置項的修改不會影響到那些與其無關的配置項
- DRY(Don't Repeat Yourself )原則。定義好配置中的每個元素,使每個配置元素在整個系統中都是唯一的,其含義絕不與其他元素重疊
- 最少化,即配置資訊應儘可能簡單且集中。除非有要求或必須使用,否則不要新增配置項
- 避免對配置資訊的過分設計,應儘可能簡單
- 使用冒煙測試來診斷依賴於配置項的相關功能是否都能正常工作
2.5 環境管理
- 在做應用程式的環境管理時,我們需要記住的原則是:環境的配置和應用程式的配置同樣重要
- 在The Visible Ops Handbook一書中,其作者把手工配置的環境稱作「藝術作品」
- 需要考慮的環境配置資訊如下
- 環境中各種各樣的作業系統,包括其版本、修補程式級別以及配置設置
- 應用程式所依賴的需要安裝到每個環境中的軟體包,以及這些軟體包的具體版本和配置
- 應用程式正常工作所必需的網路拓撲結構
- 應用程式所依賴的所有外部服務,以及這些服務的版本和配置資訊
- 現有的數據以及其他相關資訊(比如生產資料庫)
- 其實高效配置管理策略的兩個基本原則是
- (1) 將二進位文件與配置資訊分離
- (2) 將所有的配置資訊保存在一處
2.5.1 環境管理的工具
- 在以自動化方式管理作業系統配置的工具中,Puppet和CfEngine是兩個代表
2.5.2 變更過程管理
- 最後要強調的是,對環境的變更過程進行管理是必要的。應該嚴格控制生產環境,未經組織內部正式的變更管理過程,任何人不得對其進行修改
2.6 小結
- 配置管理是本書其他內容的基礎。沒有配置管理,根本談不上持續集成、發布管理以及部署流水線。它對交付團隊內部的協作也會起到巨大的促進作用
- 我們建議為下面的內容制定出一個保存基準線和控制變更的策略
- 應用程式的源程式碼、構建腳本、測試、文檔、需求、資料庫腳本、程式碼庫以及配置文件
- 用於開發、測試和運維的工具集
- 用於開發、測試和生產運行的所有環境
- 與應用程式相關的整個軟體棧,包括二進位程式碼及相關配置
- 在應用程式的整個生產周期(包括構建、部署、測試以及運維)的任意一種環境上,與該應用程式相關聯的配置