1、傳統我們的項目開發模式是產品調研提出需求,開發團隊研究決定開發方案選型。然后開始一個周期的開發,模塊開發完成之后開始模塊間的聯調。聯調結束之后打包交付給測試團隊。測試團隊,系統測試或自動化測試,然后提交bug,開發團隊修復bug,周而復始。
2、傳統的模式中,存在著較多的不確定因素。例如,開發環境、編譯環境、測試環境、生產環境,等不確定因素。人為介入打包中的不確定因素,缺乏單元測試和自動化測試的整合。從而導致的結果是,開發-測試-修復的周期較長,而且很多小的問題完全可以由單元測試進行覆蓋。
持續交付并不是某個特定的軟件,而是一個結果。這個結果要求團隊可以隨時的發布一個新的準確版本,而且要求在編譯發布的過程中進行自動化測試,通過自動化測試可以及時的發現并定位存在的bug,修復bug之后再進行快速的發布到測試環境,測試團隊直接進行測試。與傳統模式的區別在于持續交付可以提前發現bug的存在和快速修復而不必等到測試人員的介入之后才發現。持續交付分解出來就是“持續”和“交付”。 ?持續 :持續要求任何時,候任何情況都能進行準確的發布,做到準確的發布需要注意以下幾個關鍵點。
持續應該是一個周期性的,可以是每天的某個時間點,也可以是某次代碼的提交,或者某次人為觸發。所以人工進行構建是不可能的,需要自動化的構建,自動化要求構建的任何一個流程都必須以腳本的形式運行,代碼檢出、代碼構建、各模塊代碼單元測試、集成測試、UI自動化測試等。
發布的程序版本不允許是各個模塊在開發環境編譯出一個版本作為交付,而要求在一個純凈的編譯環境中進行構建。
構建的過程應該要求最大可能的固化,例如操作系統的版本,構建環境的版本,相關的依賴等。
避免從網絡獲取相關的文件,這點以nodejs為開發或編譯的項目尤其重要,安裝node的依賴包總是一個漫長的過程,就算有國內的源,一般的項目也需要一兩分鐘的node依賴包,這不符合快速構建。
交付 : 在持續編譯的過程,使用自動化已經可以避免大多數的錯誤了。但是還是需要人為介入的系統測試,畢竟自動化的測試一般只能覆蓋到70%左右。
根據我們團隊內部推廣這種工作方式的效果來看,持續集成確實讓我們工作便利了許多, 每次代碼的構建和自動化測試讓我們及時發現存在的bug。好的工作模式也需要團隊成員的遵守,團隊成員應該積極的擁抱這種工作方式,團隊成員需要做好以下幾點。
使用版本工具例如git。git有強大的版本回溯,成員每次完成一個小的功能點進行代碼提交。合并到master分支,持續交付工具應該配置為代碼更新觸發。團隊內部應該等到持續交付流程結束之后,確認編譯、自動化測試通過之后方可進行下一個版本的提交,這樣容易定位bug。而不會導致這次bug影響團隊內其他成員的工作。
主分支的代碼bug不應該存留時間過長,避免團隊內其他成員合并代碼的時候引入其他問題。
測試驅動開發,任何一個新的功能開發都應該先寫好單元測試腳本,并積極更新自動化測試腳本。并且積極地擁抱測試,雖然你明白這個測試不通過的問題并不會引起很大的系統性問題 ,但是還是應該進行修復而不是想方設法的跳過這個自動化測試。
臨近下班的時候不要提交代碼,這主要是因為遵守第2點。
Docker已經越來越火,CICD和Devops也是Docker一個重要的場景。在持續交付中使用Docker有一下優點。
Docker強大的環境隔離性可以將環境和程序打包在一起,測試、運維,人員無需知道我們的程序是如何配置的,只需要一條docker 的命令就可以將我們的程序運行起來,這也更加容易實現持續部署。
減少編譯環境的污染,因為Docker天然的隔離性,也避免了傳統編譯環境難以配置多套編譯環境的問題。在基于Docker的持續發布中,我們可以在同一臺宿主機上同時編譯不同版本的Java項目,不同版本的Python項目,而無需任何配置,鏡像也只是從docker hub中獲取。
持續集成
在持續集成方面,我們選擇Jenkins。Jenkins是一款開源軟件,擁有眾多優秀的插件,依靠這些插件,我們可以完成一些周期、繁瑣、復雜的任務。例如我們今天分享的持續發布,雖然Jenkins解決了我們繁瑣復雜周期性的操作,但是沒有解決我們在多種環境下編譯構建的需求。而這個場景正是Docker的強項。通過Jenkins的pipeline我們可以實現代碼檢出、單元測試、編譯、構建、發布、測試等流程的自動化,而最終通過Jenkins的Docker插件將產出物構建成鏡像,方便部署到Docker環境。
持續部署
持續集成讓我們新的代碼源源不斷的構建成了鏡像,這些鏡像經歷了單元測試,自動化測試,但還沒有接受過測試團隊的嚴格測試。Jenkins是一個強大的持續集成工具,然而持續部署并不是Jenkins的強項,但是Jenkins擁有很多強大的插件。22.而且我們持續集成產出的是鏡像,所以持續的部署,我們只需要將鏡像運行起來,或者利用第三方的容器管理平臺提供的API進行部署。
本地部署應用到Docker:本地部署到Docker容器可以使用Jenkins的docker插件,下面會介紹。
部署到遠程主機的Docker、Appsoar。Docker和Appsoar都支持開啟API調用。通過現有的API我們可以運行我們生成鏡像版本。從而達到持續的部署最新版本。
部署到kubernetes。kubernetes除了可以通過API調用還可以在jenkins中配置kubectl的方式創建或更新deployments。
Docker中運行Jenkins:Docker部署Jenkins的方式簡單方便,下面我們介紹用Docker的方式運行Jenkins。
這里將docker.sock和docker的可執行文件掛載到jenkins容器中,這樣我們就可以在容器中使用docker了。
jenkins容器,默認的用戶是jenkins因為我們需要使用docker所以我們需要使用root用戶。
/var/jenkins_home的掛在卷是可選的,jenkins_home存放了所有任務、日志、認證、插件等jenkins運行后的文件??勺鰯祿謴褪褂?。
配置Jenkins
1. 解鎖jenkins:解鎖的密碼在容器的log中可以查看,或者直接查看jenkins_home指定文件
選擇插件
創建Pipeline下面我們創建一個的Jenkins的Pipeline完成簡單的cicd流程。
新建pipeline,在左側新建選擇pipeline。
在左側的Credentials中新建git和鏡像倉庫的credentials
配置pipeline,例如定時觸發,代碼更新觸發,webhook觸發等。
在pipeline script中填入下面的demo.
以下是偽代碼,僅提供思路
Jenkins pipeline的腳本語法是groovy的語法,其中docker 、Git是插件提供的能力。代碼的執行流程如下:
通過Git插件獲取最新代碼到jenkins的工作區,例如`/var/jenkins_home/workspace/pipelineDemo。
docker.image().inside是如何編譯我們的代碼呢,通過查看Jenkins的console 可以看到如下log.
通過docker插件提供的能力構建鏡像,Dockerfile存放在代碼目錄中。構建鏡像后push到鏡像倉庫,私有倉庫需要自行配置鏡像倉庫。
鏡像構建完成之后就可以刪掉舊版本,并重新運行一個新的版本。
熟悉Docker命令的朋友應該很容易理解了,原來是docker.image().inside啟動的時候會將當前的目錄掛在到容器中,然后在容器中執行./script/build.sh,這樣我們就完成了利用容器中存在的環境做單元測試或構建編譯了。
通過簡單的例子,可見Jenkins和Docker的結合給CICD帶來了足夠的便利和強大。我們需要準備的只是一個編譯的腳本,在編譯腳本中可以使用任何的環境和任何的版本。
Pipeline 介紹
Jenkins的任務兩個主要版本。
free style只是一個自動化的腳本,腳本類型為shell。所有的腳本在一臺機器上運行,需要的環境需要提前準備。配置不集中,混亂。但是一般情況下還是夠用的。
pipeline 是jenkins2的版本使用了一個基于groovy腳本的任務類型,通過一系列的stage將構建的不同部分組合成一個pipline。而且配合step可以完成異步操作。因為基于groovy可編程性更加
強大,而且腳本可以存放在源碼中,腳本的更改不需要直接到jenkins中修改。
pipeline的一些使用經驗和技巧
jenkins的資料較少,官網可以查看的內容也不多,一般的需求Jenkins內置的pipeline-syntax里面就有常用的命令生成器。可以滿足大多數需求。
在pipeline腳本調試完成之后應該將腳本以文件的形式放在源碼目錄中,這樣子方便修改。和多分支需要編譯的情況下進行互相隔離。
應該多查找下相應的插件,而不是使用sh用執行腳本的方式來解決問題。
應該將jenkins_home目錄掛在出來,如果遇上了Jenkins崩潰了可以及時的恢復數據。
應該新建一個定時的pipeline用來清理生成的鏡像,減少硬盤資源的占用。
頁面新建的pipeline,在頁面刪除之后,jenkins_home/workspace中對應的項目文件并不會被刪除。
Q:請問kubernetes怎么結合jenkins做持續集成呢?
A:部署到kubernetes。kubernetes除了可以通過API調用還可以在jenkins中配置kubectl的方式創建或更新deployments。
Q: 必須通過pipeline才能實現jenkins把代碼構建成docker鏡像么?
A:不一定,使用docker主要是方便進行編譯環境的隔離,也可以配置好NFS,構建完成之后復制到固定的服務器上,這個我們一般叫制品庫
Q:docker目前官方的私有倉庫registry并沒有提供鏡像刪除功能,請問你們的鏡像是如何進行版本管理的呢
A:? Apphouse,是我們公司的一個鏡像倉庫產品基于Docker的registry,我們擴展了刪除、復制,等功能。如果有興趣的話可以到我們公司官網獲取我們的Apphouse。
Q :Pipeline如何通過docker容器部署應用到不同的節點上去?發布遇到問題如何回滾版本的?
A:就如我前面的稿件中提到的,jenkins的能力更多的是做持續集成的功能,部署和回滾并不是Jenkins的強項,特別是回滾單依靠jenkins很難做到完美的方案。但是部署到不同的Docker的節點上,可以使用第三方的管理平臺,例如Appsoar和卡k8s提供的API能力,可以進行部署。jenkins直接調用curl命令執行容器管理平臺提供的API。
Q: pipeline的每個環節的報告如何快速獲取?比如代碼靜態檢查,工程構建,測試報告等等?
A:http://jenkins:8080/job/clearImages/86/wfapi/
通過jenkins這個API,可以獲取一些狀態和時間信息,至于詳細的代碼靜態檢查,每種語言都有不同的語法檢查。需要自行配置。當然詳細的需要查看輸出日志。
Q:怎么觸發工作流的?
A: jenkins pipeline提供了三種方式(如果安裝了SCM的插件可能有其他的方式觸發),進入到pipeline的設置頁面中的分別有。wbhook(觸發遠程構建 (例如,使用腳本))、定時觸發(Build periodically)、代碼更新觸發(Poll SCM)
Q: jenkins的編譯環境是怎么處理的,實際用戶的編譯需求和環境都不一樣。
A:用戶需要清楚你使用的編譯環境的基本情況,例如golang的編譯環境,容器中的GOPATH是在什么位置,你需要將你ln到什么目錄的代碼放置在什么位置才能夠編譯,需要用戶自己去研究構建環境的使用,
Q: jenkins里的有用戶權限管理嗎,貴公司的ci cd是怎么實現用戶隔離的,每個用戶只能看到自己的項目。
A:jenkins當中并沒有用戶權限。公司在研發的產品中,有一個虛擬的概念叫用戶組,對應的是k8s中的一個或多個namespaces。管理員將成員用戶添加到這個用戶組中,組內成員創建的資源(pipeline、集群、服務,等)在組內是可見。用戶組來進行邏輯概念上的隔離
Q:貴公司jenkins和kubernetes是怎么結合使用的?是什么的部署形式?
A:我看到很多朋友都提問了,jenkins如何跨主機部署或者如何部署到kubernetes集群,如何回滾。jenkins對這方面的能力比較弱,僅僅能夠支持kube-api-server的調用而已,如果完全依靠jenkins是很難完成需求,所以我們的產品當中有一個專門對接kubernetes的deploy的模塊,一個應用商店的模塊,一個封裝了jenkins的uflow模塊,uflow模塊向應用商店獲取模板并根據當前編譯構建出來的鏡像tag號替換模板,并交付給deploy模塊創建。回滾和升級都由deploy模塊負責。這樣各自分開,各司其職。
內容分享來自于 ?有容云Docker技術交流微信群