前言
Deployment Pipeline 為 CI 的核心,能完整呈現軟體交付的整個過程。從程式碼完成後的提交、建置、部署與測試到正式的發布,除了可以清楚知道整個歷程外,也可即時得知提交進度。
那我們該如何根據團隊與不同產品去設計整個 Pipeline?此章的重點就在談這件事情。
7.1 簡單的部署流水線
此節以實際例子來簡易 OverView 在 Pipeline 設計上會有那些環節與實際情境。書中例子以Curise為範例,他就像今日我們很常聽到 Jenkis,是一個以 Java Base 開發的持續整合工具。其程式碼高達 5 萬行,而自動化單元測試及整合測試 Case 就多達 2350 個,端對端測試為 140 個,在架構也算蠻龐大的軟體系統。
但他在 2010 年就停止維護了,有興趣了解可以到他的官方網站。Curise 在 2010 年停止維護後更名為 GoCD,並走 Open Source 開發。並將 Source Code 放置Github。
7.1.1 GoCD 簡單的產品研發流程
GoCD 算典型的持續整合代理伺服器架構,其架構如下,GoCD Server 提供使用者 UI 及 Pipeline 腳本控制及指派工作,讓 Agent 去執行 Pipeline 過程中需要執行的 Command(此處簡單帶過)。另外一提,他使用的版控工具為 Mercurial 不是一般主流的 Git。
維護此產品的團隊人數約為 12 人,產品的交付其中與迭帶週期為一周。在這麼快速的迭帶週期,團隊也使用 CICD,在每個迭帶結束後,用新版本替換掉目前團隊在使用的舊版本,並在每兩個迭帶後將試用版本部署到公司內部的公用伺服器,若公司內部試用版本使用到一個品質檢測標準,一周後再將版本交給企業試用。其週期如下圖所示,
- 白正方形:單周 Blood 版本(團隊)
- 灰正方形:雙周 Alpha 版本(公司)
- 白圈:雙周 Beta 版本(外部企業)
- 大圓圈:全球發布
7.1.2 初始 Pipeline 設計
GoCD 的 Pipeline 設計是 Base on 六步提交法理論,六步如下
- 第一步: Clone 成功版本至本地端
- 第二步: 修改程式碼
- 第三步: 本地端 Build && Test
- 第四步: Pull Merge 其他人程式碼再跑一次 Build && Test
- 第五步: 提交
- 第六步: 進 Pipeline
感覺六部提交法是針對新的小碼農制定的口訣,避免小碼農 Clone 錯誤的程式碼或是沒有做好 Build Test 就提交程式碼,會 Focus 在個人建置部分。
我們來看 GoCD 的 Pipeline 設計如下圖,整個提交整合與部署分為八個 Stage 站別,有手出現的 Icon 代表人為去介入
基本上每個站別都只有一類任務類型,
- 1.提交建置:Build 與 單元集成測試
- 2.次級建置:End To End 測試(Windows && Linux)
- 3.將打包好的檔案部署到 UAT 環境
- 4.測試人員驗證完後 Tag 驗收通過,並對 Pipeline 點擊繼續
- 5.做自動化性能測試(此處沒說明做什麼性能測試)
- 6.將 Alpha 版本部署到公司內部伺服器給團隊試用
- 7.試用 OK 後發布 Beta 版本給外部企業試用
- 8.外部企業試用試用完成後正式發布
基本上這 Pipeline 設計大部分專案情境可能都會經過這些步驟,只是也許後面部署與測試順序不一定會完全相同。例如有些企業會覺得 UAT 測試完後其實就可以上 Production,但 GoCD 為了嚴謹在部署測試上又多了好幾個站別,確保 Product 能完全運行順利。
另外值得一提的,在這個設計中,GoCD 在單元集成測試的時間非常長,有五個集成測試,基本上每個集成測試要花 15min,而第二站別的次級建置端對端測試也多達 140 個測試項目,需要最長時間為 30min....
7.1.3 Pipeline 狀態解析
管線運型實際狀況如下,可看到在建置編號 12 版本,在 UAT 部署就停了下來。也許這建置版本並沒有新功能,所以可以在這階段就停止。而建置編號 13 在次級建置跳過,有可能因為 12 還沒完成。至於此處是手動按停止還是自動停止就不太清楚。
不過此節要表達的是,再多 Job 管線運行上,會根據不同狀況管線過的 Stage 狀況也會不太一樣。
7.2 Pipeline 的設計與使用
在介紹完 GoCD Pipeline 的實際使用狀況,大體上應該會曉得基本 Pipeline 會有什麼工作需要運行。那我們該如何透過設計去優雅的使用 Pipeline 呢?
7.2.1 Pipeline 的設計原則
書中提到有 5 個觀念去設計 Pipeline
- 一次建置,多次使用。Pipeline 上的任務要產生部署使用的檔案,盡量在前面的站別就一次建置完成,並可直接讓後面的站別做使用。盡量不要在後面在別再做重複性建置。另外如果後續的站屬如果要使用此編制檔案,也必須此部署檔案來源是與上流站別是同一份。
- 與業務邏輯松耦合。簡單來說在就是不要為了方便,將一些部署所需使用的腳本或資料放在 Pipeline Server 上,盡量與 Pipeline Server 不要有編譯耦合的設計。相反,若有相依檔案或腳本,我們必須存放在存取庫中,照樣就可以輕鬆對這些腳本設計做修正。簡單來說,對於 Pipeline,他就像是調度、執行與紀錄者,他只需要知道整個調度流程,不需要知道如何建置與部署軟件需要自己提供哪些東西。
- 並行化原則。如果有五個自動化測試任務,我們也可以設計並行 Pipeline 同步跑這五個測試任務,並即時提供結果訊息,從而修正問題。若使用併行,整體等待回應的時間就能大幅收短。就像前面提到 GoCD 有五個測試集成,若使用並行化原則就能大幅縮短測試時間。
- 快速回應結果。如果資源較貧乏(例如 Runner 規格特爛),在 Stage 的設計,我們可以將依些運行較快的自動化驗證優先做執行,較慢與消耗資源較多的放在後面執行。感覺這邊得意思 花較長時間的測試,就放在越接近正式上線前做,來縮短前面開發測試時間。
- 重要的回應結果優先。呼應第四點,雖然為了達到快速回應結果將一些較快的測試放在前面做,但依然要以重要優先權高的為主。
7.2.2 團隊紀律
1.立即暫停原則
Pipeline 一出問題,團隊需要有人立即去處理,而不是放任他不管。再問題修復前,禁止任何人提交新的程式碼。
2.安全審核原則
所有代碼與軟件包都需要有偷過板控及審核完畢才可使用。
7.3 Pipeline 平台的組成
這章節主要述說 Pipeline 的主要組成區塊
7.3.1 工具鏈整體架構
書中提出的圖有點難去了解,在這我拿一張以 Github 結合 Jenkis 的架構圖去輔佐解說(Jenkis 那張圖先不管架構 Solution 是否為最好)。
Pipeline 整體架構主要分成、唯一信受源(程式碼與打包物存取庫)、調度及展示(調度器)以及基礎支撐服務(測試、部署等實際執行環境..)
1.唯一信受源
在 Pipeline 過程中,團隊角色若對任何訊息產生質疑時,要做追溯都應該要能追回到存取庫裡的產出物(要部署檔案),而在存取庫中的打包檔案都可以找到對應程式碼及他相依的類別庫檔案,或是能找到下載的 URL Source。
2.調度及展示(Pipeline)
能接受不同的服務基礎平台,且具有調度不同任務,完成整個交付流程的功能。並此能展示整個過程的歷史訊息。
3.基礎支撐服務
一間較大的公司具有相對應的建置、測試及部署的服務。規模較不大的通常前兩個通常就直接在一個 Runner Execute 直接做掉。那如果是前者,在 Pipeline 設計上就要考慮如何去與這些基礎支撐服務去連通與協作,讓整體 Pipeline 過程中達到最大的效益性。
7.3.2 平台應具有的基本能力
Pipeline 事團隊多角色的統籌協作系統,因此關注的是軟體在 Pipeline 的流動效率,包含部署與上線,過程能精準展現個環節的狀態與訊息,並能在不增加團隊負擔情況下自動收集各環節產生的數據。例如,衡量某一功能的開發週期。
此章節提到重點就下述兩點,
- 1.追溯能力
- 2.重新建置能力
針對 1 不多說,簡單來說就是對於事件能查詢他所有的歷程。對於 2,只要存取庫程式碼依舊存在,就算遇到版本出問題,依舊能再次修改重新做自動部署。又或是自動化失敗因為對應服務環境出問題,在對應環境 Recovery 後,能再次重新運行測試。
7.3.3 工具鏈建設策略
上述 7.3.1 圖中提到的平台架構,可看出他是由不同的工具與子系統組成。因此我們可以根據公司的習慣與策略去客製設計。例如 GoCD 團隊因為在自動化測試量較龐大,因此就自行開發一個自動化測試分組插建,由此插件自動將所有測試分配到不同任務哩,並將這些任務分配到多個測試環境中執行。但對更大型的公司,其環境會更加複雜,其各產品組件之間的關聯關係也會更加龐大複雜。為了發揮持續交付的威力,上述提到的各類支撐服務雲端化也成為必要選項。例如 AWS、Facebook 與 Google 都具有自己的 DevOps 平台工具鏈,甚至將其中一部分工具開放給 Open Source。
那此服務系統間個詳細的關係是什麼? 7.4 章節會述說這件事情。
7.4 基礎支撐服務雲端化
大多大公司服務端程序部署頻率都非常快,幾乎都又自己的雲化支撐服務,如下表
7.4.1 基礎支撐服務協過過程
此章節為稍微大致講解整個管線與基礎建置服務互動的過程,大分類上分三個步驟來看,
第 0 步:環境準備(yml 設定)
這部白話一點就是整體部署有哪些設定及有哪些基礎服務建設,針對 Stage 任務對應相關設定指派相對應基礎建設服務準備。
第 1 步:提交建置(建置,測試)
將 Source Code 交至相對應服務做健置與測試,建置管理服務會將代碼從程式存取庫中提出,然後在建置環境建置打包後,放入成品庫。
接著部署管理服務根據 Pipeline 定義將編譯好的成品,放到測試環境測試。如果測試需要一些比較特別的設定,則同時從部署配置讀取相關配置,成功後就開始執行 Pipeline 的測試任務。
第 2 步:次級建置(部署,測試)
當測試完成後,部署管理服務會再從成品庫中拿去成品,並從部署配置讀取 UAT 相關部署訊息,將兩者結合,部署到 UAT 環境進行端對端測試。
第 3 步:部署生產環境
當次級建置 UAT 測試完成後,部署管理服務會再次從成品庫取出成品,並讀取配置訊息,部署到正式環境。
7.4.2 建置管理服務
構成分三個區塊
- 任務管理
- 調度
- 執行器
每個區塊服務都有柱列緩衝,任務管理將任務交給調度器後,調度器會根據一定的調度算法選擇建置任務將其發送相對應的執行器編譯。例如 c#代碼若為 Net Framework 則指派到 Windows 環境下編譯,C++則指派到 Linux 下環境編譯。而集群管理器則是管理這些執行器的建立與狀態管理(繁忙、空閒、失去連線..)。
執行器為建置任務的代理,集群中可以有多個執行器,每個執行器會根據收到訊息對應的存取庫 URI 檢出代碼並根據要求編制建置任務。建置完成後會將指定產物(部署需用檔案)放到成品庫中。並向 Pipeline 回報執行結果。
另外可以看到圖中左邊 Request 輸入點有個人頭,代表這架構也允許工程師在本地編寫期間就可以直接使用此服務。
7.4.3 自動化管理服務
構成分三(四)個區塊
- 任務管理
- 調度
- 執行器
- 測試健康管理
針對任務管理、調度與集群管理猶如 7.4.2 所說,大致上是一樣的意思,只是編制任務變成測試任務。值得一提的是測試健康管理。當測試在不同節點或資源條件下,因為失敗重複執行太多次(書中寫 1000 次)。
此時測試健康管理器就會將不穩定的 Case 拉到不穩定池並通知團隊做處理。這邊健康管理器英文對應一時查不太到....所以如何實作也不太清楚。
7.4.4 軟件部署管理服務
雖然在 Pipeline 過程中的測試都沒問題,但也有可能到了實際正式環境會出錯。原因在於測試環境與正式環境還是會有一定的差異性。
書中舉過內很多大型企業的生產環境用的 J2EE 應用服務器都是商業軟件,但因為過於笨重,所以用語法檢查就不嚴格的 Tomcat。此時如果部署到企業的正式生產環境,就會產生有些頁面因為 Html 標籤不匹配而發生錯誤。
好,上述講一講不是下圖重點..下圖要表達的是,因為為了協調運維部門與產品部門的合作。之間的接口建議有個正式產品庫及上線單。此時運維部門就可以根據上線單,從正式產品庫拉取相對應的產品至正式(生產)環境步數。
7.4.5 基礎環境管理服務
為建置、測試、部署管理提供環境準備與監控服務。能接受這三種環境的請求為期準備相對應的環境。隨著 Docker 技術成熟,配置基礎環境慢慢以 Docker Image 形式,需要時直接啟動,並提供服務。
7.5 企業成品庫的管理
企業成品庫是部署流水線工具鏈中企業的受信源之一,也是企業信息管理中的一個重要節
點。只有通過安全驗證的軟體包才會被納入成品庫,並且安全驗證部門也應定期對存儲的
對存儲的內容作安全掃描及清理。
7.5.1 成品庫的分類
- 臨時軟體包庫(A)
用於存儲團隊開發並通過流水部屬線生成程式碼的所有軟體包。 - 正式軟體包庫(B)
用於存儲通過流水線部署且經過安全驗證,被確認能夠發布到生產環境或使用者的軟體包。 - 外部軟體包庫(C)
指該軟體包的程式碼並非由團隊管理或維護,但在開發中所使用到的其他軟體包。這些軟
體包通過互聯網或是第三方取得,亦將其存儲在成品庫中。
外部軟體包一般存儲的形式可能包含 3 種:
(1) 以二進制的方式保存。
(2) 以程式碼副本的方式保存。
(3) 以外部連結地址的方式保存。 - 臨時鏡像庫(D)、正式鏡像庫(E)、外部鏡像庫(F)
基本上同軟體包庫,只是以鏡像的方式作存儲。
7.5.2 成品庫的管理原則
成品庫中,每個成品都應該有標示,並且連同其來源、組成的部件以及用途等,一起保
存為該成品的信息。所有成品都要能夠追溯至源頭, 包括臨時成品庫中的成品。
7.6 多種多樣的部署流水線
7.6.1 多組件的部署流水線
若一個軟體產品由多個組件建置而成,每個組件都有獨自的程式碼倉庫,並且每個組件
由一個單獨的團隊負責開發與維護,整個產品的部署流水線的設計通常與下圖相似。
每個組件的部署流水線成功以後,都能觸發下游的產品集成部署流水線。而這個集成部
署流水線的打包階段,會自動從軟體包庫中獲取每個組件最近成功的軟體包,然後對其
進行產品打包,再觸發集成部署流水線的後續階段。
7.6.2 個人部署流水線
每名工程師創建了自己專屬的部署流水線,用於個人在未推送程式碼到團隊倉庫之前的
使用。個人的部署流水線並不會部署到團隊共同擁有的環境中,而是僅覆蓋個人開發環
節。
工程師通過部署流水線的模板功能,複製一份團隊部署的副本。並僅保留兩個階段(提
交建置、次級建置)的內容。令工程師能夠監聽自己程式碼倉庫的變化,並且自動化去
觸發。當開發人員提交程式碼到個人倉庫時,都會自動觸發個人專屬的部署流水線。
這樣做的好處有 3 個:
- 個人部署流水線與團隊的部署流水線共享建置及測試環境。
- 保證每個工程師都能利用到相同的測試資源,加快個人檢驗的速度。
- 個人部署流水線的測試用例與團隊的部署流水線的驗證集合相同,因為是相同的建置資源,若是發生建置失敗,則可以容易的定位到問題點。
7.6.3 部署流水線的不斷演進
截止到 2018 年 4 月,GoCD 的社區版本每月會發布一次正式版,而其團隊的複雜的部署流
水線設計也已演變如下圖所示:
構置 Linux 包這個部署流水線中,包含兩個階段。第一個階段是 build-no_server。多
個任務並行執行,構置組成 Server 所需的多個 Jar 包,也並行執行 Java 測試用例和
JavaScript 單元測試用例。這體現了部署流水線盡量並行化原則。第二個階段是
build-server,使用經第一個階段己初步驗證通過的多個 Jar 包組裝成 Sever 包。
Linux 驗收測試這個部署流水線中,也包含兩個階段。第一個階段是運行高優先級的功
能測試,第二個階段是對插件部分的自動化功能測試,這體現了部署流水線的快速反饋
優先原則。
而在後續的各類測試(如驗收測試、回歸測試或者功能測試)中,被測試的二進制包均來
自前面各部署流水線的產出物,而且確保其使用同一程式碼版本。
7.7 為開發者建置自助式工具
優秀的互聯網公司採用了一種工具平台的設計理念,即為開發工程師設計他們認為好用
的工具。這種方式要求創建強大的工具平台,能夠很好地支持開發工程師做產品服務。
例如 Facebook,開發人員可以通過他們內部平台看到自己的程式碼已經發佈到哪個階
段,有多少用戶在使用。開發工程師在不需要任何人幫助的情況下,就能夠了解他的程
式碼已經發佈到哪個階段了。
例如電商公司 Etsy,開發工程師可以查看到自上次生產部署以後,每次的程式碼變更
數量,並且非常方便地查找程式碼差異。