一、持續整合是什麼?
持續整合是一種軟體開發的實踐,即團隊開發成員經常整合他們的工作,通常每個成員每天至少整合一次,也就意味著每天可能會發生多次整合。每次整合都通過自動化的構建(包括編譯,釋出,自動化測試)來驗證,從而儘快地發現整合錯誤。許多團隊發現這個過程可以大大減少整合的問題,讓團隊能夠更快的開發內聚的軟體。
持續整合指的是,頻繁地(一天多次)將程式碼整合到主幹,通過持續整合流程的進行自動化方式的構建,編譯和測試,提供可以部署釋出的單元包
持續整合的目的,就是讓產品可以快速迭代,同時還能保持高質量。
它的核心措施是,程式碼整合到主幹之前,必須通過自動化測試。
只要有一個測試用例失敗,就不能整合。
Martin Fowler說過,"持續整合並不能消除Bug,而是讓它們非常容易發現和改正。與持續整合相關的,還有兩個概念,分別是持續交付和持續部署。
二 持續整合的價值是什麼?
1、降低風險,由於持續整合不斷去構建,編譯和測試,可以很早期發現問題,所以修復的代價就少;
2、對系統健康持續檢查,減少釋出風險帶來的問題;
3、減少重複性工作;
4、持續部署,提供可部署單元包;
5、持續交付可供使用的版本;
6、增強團隊信心;
三、持續整合流程
持續整合一般的做法: 通過svn或其他工具拉取程式碼->自動化構建->自動化編譯->自動化測試->自動化部署->自動化釋出->郵件傳送通知;
四、持續交付
持續交付(Continuous delivery)指的是,頻繁地將軟體的新版本,交付給質量團隊或者使用者,以供評審。如果評審通過,程式碼就進入生產階段。
持續交付可以看作持續整合的下一步。它強調的是,不管怎麼更新,軟體是隨時隨地可以交付的。
五、持續部署
持續部署(continuous deployment)是持續交付的下一步,指的是程式碼通過評審以後,自動部署到生產環境。
持續部署的目標是,程式碼在任何時刻都是可部署的,可以進入生產階段。
持續部署的前提是能自動化完成測試、構建、部署等步驟。
測試是持續整合流程中重要的一環,也是區別去傳統的軟體開發流程中的一個重要的標誌。為什麼要有持續整合測試呢?
1、可以早點發現bug,這就是fix bug代價比較小
2、可以平滑產品,提高產品質量
3、可以讓團隊的每個人瞭解產品的質量狀態
4、每天都有持續整合測試的報告發布
5、開發者對自己提交的程式碼測試情況有比較清晰的瞭解
6、可以有效地解決在QA人手不足的情況
7、儘可能地把測試自動化,讓持續整合測試系統去執行這些自動化測試的case
以前團隊工作方式
1、打包,等待maven編譯打包 2、釋出測試環境,手動重啟服務 3、通知測試組測試(郵件、用嘴巴喊等等方式...) 4、一頓grep查Exception,修復BUG,然後重複1、2、3、4 5、到達特殊的日子時,配合運維部署團隊到測試環境手動copy最新版WAR包到生產環境,23點的一瞬間執行一個指令碼,時刻盯住指令碼執行結果,最後驗證
我們可以發現很多問題: 1,編譯打包的過程浪費開發資源,一次測試部署正常10到20分鐘,那出現問題的情況...
2,測試長時間怠工,資源利用不充分,處於一人幹活多人旁觀低績效狀態
3,研發與測試的溝通方式高成本低效率
4,BUG反饋方式低效
5,生產環境得不到有效的管控以及安全保障,人工浪費如果產品或者銷售想要給客戶演示測試環境,得到的結果可能是測試暫時不可用或者稍微等15到20分鐘,是否能計算出他們的心理陰影面積?
DevOps的中心思想在於提高產品各個階段的產出效率減少或者避開團隊間的溝通障礙,推動產品的快速迭代,“快速失敗”,從而實現持續交付、持續部署。而持續整合只是DevOps中的一個環節,下圖清晰描述了CI各個週期活動。
我們可以發現較多優點: 1、流程全自動化,減少重複性的手工操作2、持續釋出測試,時刻保持可釋出的產品
3、團隊、高層對專案、產品的進展清晰可見,把控風險
4、資源效率有效利用,流動效率更快
因此,我們要做到持續整合,我們需要:
1、一套持續整合工具,大體可分為雲整合與本地化整合系統,雲整合比如Travis CI、cloudbees的雲整合等,本地化整合主要是開源Jenkins的搭建,如果需要大規模部署Jenkins且有預算可使用Jenkins商業版
2、自動化測試工具、良好的測試用例編寫
3、版本控制系統,git、gerrit推薦
4、構建、測試失敗反饋機制,郵件、自動化運維(AI...)、日誌收集分析系統
5、一套需求、產品、開發、測試、部署、運維共同使用的敏捷研發管理系統,市場上有阿里雲效、騰訊的TAPD等
流程(A)
根據持續整合的設計,程式碼從提交到生產,整個過程有以下幾步。
1 提交
流程的第一步,是開發者向程式碼倉庫提交程式碼。所有後面的步驟都始於原生程式碼的一次提交(commit)。
2 測試(第一輪)
程式碼倉庫對 commit 操作配置了鉤子(hook),只要提交程式碼或者合併進主幹,就會跑自動化測試。
測試有好幾種。
單元測試:針對函式或模組的測試 整合測試:針對整體產品的某個功能的測試,又稱功能測試 端對端測試:從使用者介面直達資料庫的全鏈路測試 第一輪至少要跑單元測試。
3 構建
通過第一輪測試,程式碼就可以合併進主幹,就算可以交付了。
交付後,就先進行構建(build),再進入第二輪測試。所謂構建,指的是將原始碼轉換為可以執行的實際程式碼,比如安裝依賴,配置各種資源(樣式表、JS 指令碼、圖片)等等。
常用的構建工具如下。
Jenkins Travis Codeship Strider Jenkins 和 Strider 是開源軟體,Travis 和 Codeship 對於開源專案可以免費使用。它們都會將構建和測試,在一次執行中執行完成。
4 測試(第二輪)
構建完成,就要進行第二輪測試。如果第一輪已經涵蓋了所有測試內容,第二輪可以省略,當然,這時構建步驟也要移到第一輪測試前面。
第二輪是全面測試,單元測試和整合測試都會跑,有條件的話,也要做端對端測試。所有測試以自動化為主,少數無法自動化的測試用例,就要人工跑。
需要強調的是,新版本的每一個更新點都必須測試到。如果測試的覆蓋率不高,進入後面的部署階段後,很可能會出現嚴重的問題。
5 部署
通過了第二輪測試,當前程式碼就是一個可以直接部署的版本(artifact)。將這個版本的所有檔案打包( tar filename.tar * )存檔,發到生產伺服器。
生產伺服器將打包檔案,解包成本地的一個目錄,再將執行路徑的符號連結(symlink)指向這個目錄,然後重新啟動應用。這方面的部署工具有 Ansible,Chef,Puppet等。
6 回滾
一旦當前版本發生問題,就要回滾到上一個版本的構建結果。最簡單的做法就是修改一下符號連結,指向上一個版本的目錄。
流程(B)
實現持續整合,一般需要以下內容:
1. 具有版本控制功能的程式碼庫
例如:SVN, Git。相信現在的專案沒有不對程式碼進行版本管理的,所以這方面內容大家也應該非常熟悉。在這裡不再詳述。
2. 構建工具
在持續整合的過程中,需要對已存在的或者新提交的程式碼進行編譯、打包等操作。這樣,就需要構建工具幫助構建一個編譯環境,並對程式碼進行編譯、整合、打包等操作。而構建的方式越簡單越好,最好是一句命令就可以啟動構建。現在,各種語言都有自己的構建工具,例如Java中的Maven、Gradle、Ant,前端中的Grunt、Gulp等等,好好利用這些工具,就能幫你完成這部分工作。
3. 測試
測試是持續整合中重要的一環。程式碼提交前,需要在本地執行單元測試,通過測試後再提交程式碼。構建完成後,需要執行全部測試(單元測試,功能測試,端到端測試)以確保產品質量。如果有一個測試沒有通過,那麼這次提交的程式碼不能進入主幹;或者這次構建的產物是一個失敗的構建品,不能用於釋出。另外,由於持續整合依賴於這些測試去保證產品質量,所以測試的覆蓋率要儘可能高。測試覆蓋率不夠高(包含程式碼覆蓋率和功能覆蓋率),就無法充分反映程式碼的變動是否對系統帶來影響。而低覆蓋率的測試,壓根就無法保證產品質量。當上線的時候才發現問題就太遲了。
4. CI工具
CI工具的作用是將整個CI過程管理起來並自動化,結果視覺化。部分工具還結合了CD(持續交付)的功能。現在已經有很多CI工具去滿足你不同的需求,例如Jenkins,專為Github開源專案提供的Travis,.Net用的CruiseControl.Net。他們各有特色,根據自己的需求選擇適合自己的工具即可。
好了,當集齊以上內容後。我們用一個例子來介紹一下一個典型流程是怎樣的。
例子背景描述
假設我們現在有一個產品P,以war包形式釋出,由三個模組module A, module B, module C構建而成。三個模組的關係為:A和B為獨立模組提供不同功能。C依賴A和B,然後構成產品P。我們使用了Git作為我們程式碼庫的版本管理工具,用Java進行開發,maven作為我們的構建工具。在每個模組裡,有我們基於JUnit寫的單元測試程式碼。獨立於三個模組外,有一塊程式碼,也是基於JUnit寫的,作為我們的功能測試程式碼(整合測試)。
整合程式碼
當我們完成開發工作,需要提交程式碼到程式碼庫前,我們至少需要在本地跑一次單元測試,在保證全部測試通過後,才可以將程式碼提交至我們的程式碼庫Git上面去。例如,在我們上面描術的專案中,我對module A的程式碼進行了修改,那我最起碼得在本地執行一次mvn test(執行Maven命令,test代表將會執行到maven default生命週期中從validate到test階段), 執行成功後,我才會將程式碼commit and push到遠端Git庫上去。要做到這樣效果的話,就需要保證單元測試程式碼也同步完成。而在極限程式設計中(XP),人們比較傾向於測試驅動開發(TDD, Test-driven Development)的實踐,通過提前寫好自動化的單元測試,保證好每一步功能開發的質量。
自動構建
通過CI工具,可以設定一個勾子,當程式碼提交後觸發相應構建。例如,我們提交了module A的程式碼時,Jenkins會掃描到我們這次提交,勾子觸發module A的構建。這個過程會做如下操作:
1,Jenkins呼叫Git外掛,從Git庫上下載最新程式碼;
2,Jenkins呼叫Maven外掛,執行Maven命令(一般為mvn install,如果需要上傳至遠端Maven庫,也可以執行mvn deploy)對該模組進行構建。經過編譯、通過單元測試後,便可以打包並安裝到本地Maven庫,以供其它依賴所用。這次構建成功,意味module A在模組自身的單元測試範圍內是正常的。
3,因為module A是包含在產品P裡面,所以,也需要回歸一產品功能測試。由於module C依賴A,並構建成產品。所以在CI工具裡面,我們需要配置好在module A構建成功後,自動觸發module C的構建,經過類似步驟1、2這樣的構建後,最終會生成產品P的war包。而C的構建成功,只代表著通過了module C自身的單元測試,還不能對生成的war包進行功能測試。然後就要看我們下一步的工作--自動部署了。
自動部署
在功能測試之前,我們需要在CI工具裡配置一項任務,用於將最新構建出來的產品包部署到測試工環境中去。這個任務由產品構建任務成功而被觸發,而部署方式根據不同使用方式及不同的實際情況而多種多樣。例如通過指令碼將新構建的war包上傳至指定位置,等待web容器自動掃描及部署。能或者產品有自己的安裝指令碼,我們在任務中配置好執行安裝指令碼,就可以自動將產品部署到指定的測試環境中去。
功能測試(整合測試)
當部署成功後,真正的功能測試就可以開始了。一般情況下,我們可以獨立出一塊程式碼,基於JUnit編寫好我們的功能測試程式碼(JUnit是作為測試的入口以及基本測試框架。如果你的需求比較複雜,那你完全可以將其它三方框架與JUnit整合使用)。功能測試過程和構建過程非常相似,均是依賴Git和Maven去完成:
1,Jenkins呼叫Git外掛,從Git庫上下載最新程式碼;
2,Jenkins呼叫Maven外掛,執行Maven命令:mvn clean test。
區別在於功能測試階段,Maven只執行到default生成周期的test階段,不會執行後面的package和install。因為它只需要Maven幫忙執行測試程式碼即可,它本身沒有什麼可以構建的。
P.S.
如果還需要更復雜的端到端測試的話,可能就需要準備更復雜的部署指令碼,或者預先準備好整套端到端測試環境,後面只需要部署好war包即可。但無論怎樣,最終原來理還是相同。
交付
當新提交程式碼後構建出來的產品包,通過了各種各樣殘酷的測試後,就說明這個包是穩定的,能達到基本交付條件的(前提是自動化測試的覆蓋率足夠高,當然,有一些極端的情況需要人工測試的另說)。那麼,我們就可以將這個包放到指定目錄作為交付品,供其它測試團隊獲取並進行進一步的測試,甚至供生產環境部署使用。
總結
持續整合作為極限程式設計中的一個實踐,現在已被很多公司使用。但是,使用持續整合,並不是說你得接受極限程式設計的全部東西。相反,它可以獨立開來,與其它實踐結合使用。 持續整合是敏捷開發中快速迭代的重要保證。 自動化測試是持續整合中重要一環,要真正用好持續整合,就要儘量提高自動化測試的覆蓋率。
以上兩種流程A,B都是一些公司常用的模式,大同小異,大家僅供參考。