網際網路軟體的開發和釋出,已經形成了一套标準流程,最重要的組成部分就是持續內建(Continuous integration,簡稱CI)。
一、概念
持續內建(Continuous Integration)指的是,頻繁地(一天多次)将代碼內建到主幹。
持續內建的目的,就是讓産品可以快速疊代,同時還能保持高品質。
它的核心措施是,代碼內建到主幹之前,必須通過自動化測試。隻要有一個測試用例失敗,就不能內建。
它的好處主要有:
1. 提高開發效率
持續內建可以把工程師從繁瑣的任務中解放出來,提高工作效率。并且能有效減少釋出版本中的錯誤和 Bug 數量。防止分支大幅偏離主幹。如果不是經常內建,主幹又在不斷更新,會導緻以後內建的難度變大,甚至難以內建
2. 快速發現并定位 Bugs
通過各種例行測試,您的團隊可以在問題變嚴重前就發現并定位到程式的 Bugs。減少由程式錯誤帶來的損失。每完成一點更新,就內建到主幹,可以快速發現錯誤,定位錯誤也比較容易。
3.更快速的釋出更新
持續內建可以幫助您的團隊更快速、更積極的釋出程式更新程式。在釋出時可自動完成大量重複工作完成,節省人力。
持續內建的目的,就是讓産品可以快速疊代,同時還能保持高品質。它的核心措施是,代碼內建到主幹之前,必須通過自動化測試。隻要有一個測試用例失敗,就不能內建。
Martin Fowler說過,"持續內建并不能消除Bug,而是讓它們非常容易發現和改正。"
與持續內建相關的,還有兩個概念,分别是持續傳遞和持續部署。
二、持續傳遞
持續傳遞(Continuous delivery)指的是,頻繁地将軟體的新版本,傳遞給品質團隊或者使用者,以供評審。如果評審通過,代碼就進入生産階段。
持續傳遞可以看作持續內建的下一步。它強調的是,不管怎麼更新,軟體是随時随地可以傳遞的。
持續傳遞在持續內建的基礎上,将內建後的代碼部署到更貼近真實運作環境的「類生産環境」(production-like environments)中。比如,我們完成單元測試後,可以把代碼部署到連接配接資料庫的 Staging 環境中更多的測試。如果代碼沒有問題,可以繼續手動部署到生産環境中。
三、持續部署
持續部署(continuous deployment)是持續傳遞的下一步,指的是代碼通過評審以後,自動部署到生産環境。
持續部署的目标是,代碼在任何時刻都是可部署的,可以進入生産階段。
持續部署的前提是能自動化完成測試、建構、部署等步驟。它與持續傳遞的差別,可以參考下圖。
四、流程
根據持續內建的設計,代碼從送出到生産,整個過程有以下幾步。
4.1 送出
流程的第一步,是開發者向代碼倉庫送出代碼。所有後面的步驟都始于本地代碼的一次送出(commit)。
4.2 測試(第一輪)
代碼倉庫對commit操作配置了鈎子(hook),隻要送出代碼或者合并進主幹,就會跑自動化測試。
測試有好幾種。
- 單元測試:針對函數或子產品的測試
- 內建測試:針對整體産品的某個功能的測試,又稱功能測試
- 端對端測試:從使用者界面直達資料庫的全鍊路測試
第一輪至少要跑單元測試。
4.3 建構
通過第一輪測試,代碼就可以合并進主幹,就算可以傳遞了。
傳遞後,就先進行建構(build),再進入第二輪測試。所謂建構,指的是将源碼轉換為可以運作的實際代碼,比如安裝依賴,配置各種資源(樣式表、JS腳本、圖檔)等等。
常用的建構工具如下。
Jenkins和Strider是開源軟體,Travis和Codeship對于開源項目可以免費使用。它們都會将建構和測試,在一次運作中執行完成。
4.4 測試(第二輪)
建構完成,就要進行第二輪測試。如果第一輪已經涵蓋了所有測試内容,第二輪可以省略,當然,這時建構步驟也要移到第一輪測試前面。
第二輪是全面測試,單元測試和內建測試都會跑,有條件的話,也要做端對端測試。所有測試以自動化為主,少數無法自動化的測試用例,就要人工跑。
需要強調的是,新版本的每一個更新點都必須測試到。如果測試的覆寫率不高,進入後面的部署階段後,很可能會出現嚴重的問題。
4.5 部署
通過了第二輪測試,目前代碼就是一個可以直接部署的版本(artifact)。将這個版本的所有檔案打包(
tar filename.tar *
)存檔,發到生産伺服器。
生産伺服器将打封包件,解包成本地的一個目錄,再将運作路徑的符号連結(symlink)指向這個目錄,然後重新啟動應用。這方面的部署工具有
Ansible,
Chef Puppet等。
4.6 復原
一旦目前版本發生問題,就要復原到上一個版本的建構結果。最簡單的做法就是修改一下符号連結,指向上一個版本的目錄。