《基于Docker的Jenkins持續(xù)交付實(shí)踐》要點(diǎn):
本文介紹了基于Docker的Jenkins持續(xù)交付實(shí)踐,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
講師介紹:葉峰
有容云資深前端開(kāi)發(fā)工程師
主題簡(jiǎn)介:
1.Jenkins pipeline基礎(chǔ)概念
2.Jenkins pipeline如何帶來(lái)工作便利
3.基于容器的Jenkins CI流程
4.Jenkins、Docker、Kubernetes整合的集成部署
傳統(tǒng)我們的項(xiàng)目開(kāi)發(fā)模式是產(chǎn)品調(diào)研提出需求,開(kāi)發(fā)團(tuán)隊(duì)研究決定開(kāi)發(fā)方案選型.然后開(kāi)始一個(gè)周期的開(kāi)發(fā),模塊開(kāi)發(fā)完成之后開(kāi)始模塊間的聯(lián)調(diào).聯(lián)調(diào)結(jié)束之后打包交付給測(cè)試團(tuán)隊(duì).測(cè)試團(tuán)隊(duì),系統(tǒng)測(cè)試或自動(dòng)化測(cè)試,然后提交bug,開(kāi)發(fā)團(tuán)隊(duì)修復(fù)bug,周而復(fù)始.傳統(tǒng)的模式中,存在著較多的不確定因素.例如,開(kāi)發(fā)環(huán)境、編譯環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境,等不確定因素.人為介入打包中的不確定因素,缺乏單元測(cè)試和自動(dòng)化測(cè)試的整合.從而導(dǎo)致的結(jié)果是,開(kāi)發(fā)-測(cè)試-修復(fù)的周期較長(zhǎng),而且很多小的問(wèn)題完全可以由單元測(cè)試進(jìn)行覆蓋.
持續(xù)交付并不是某個(gè)特定的軟件,而是一個(gè)結(jié)果.這個(gè)結(jié)果要求團(tuán)隊(duì)可以隨時(shí)的發(fā)布一個(gè)新的準(zhǔn)確版本,而且要求在編譯發(fā)布的過(guò)程中進(jìn)行自動(dòng)化測(cè)試,通過(guò)自動(dòng)化測(cè)試可以及時(shí)地發(fā)現(xiàn)并定位存在的bug,修復(fù)bug之后再進(jìn)行快速的發(fā)布到測(cè)試環(huán)境,測(cè)試團(tuán)隊(duì)直接進(jìn)行測(cè)試.與傳統(tǒng)模式的區(qū)別在于持續(xù)交付可以提前發(fā)現(xiàn)bug的存在和快速修復(fù)而不必等到測(cè)試人員的介入之后才發(fā)現(xiàn).持續(xù)交付分解出來(lái)就是“持續(xù)”和“交付”.
持續(xù):持續(xù)要求任何時(shí),候任何情況都能進(jìn)行準(zhǔn)確的發(fā)布,做到準(zhǔn)確的發(fā)布需要注意以下幾個(gè)關(guān)鍵點(diǎn).
1.持續(xù)應(yīng)該是一個(gè)周期性的,可以是每天的某個(gè)時(shí)間點(diǎn),也可以是某次代碼的提交,或者某次人為觸發(fā).所以人工進(jìn)行構(gòu)建是不可能的,需要自動(dòng)化的構(gòu)建,自動(dòng)化要求構(gòu)建的任何一個(gè)流程都必須以腳本的形式運(yùn)行,代碼檢出、代碼構(gòu)建、各模塊代碼單元測(cè)試、集成測(cè)試、UI自動(dòng)化測(cè)試等.
2.發(fā)布的程序版本不允許是各個(gè)模塊在開(kāi)發(fā)環(huán)境編譯出一個(gè)版本作為交付,而要求在一個(gè)純凈的編譯環(huán)境中進(jìn)行構(gòu)建.
3.構(gòu)建的過(guò)程應(yīng)該要求最大可能的固化,例如操作系統(tǒng)的版本,構(gòu)建環(huán)境的版本,相關(guān)的依賴等.
4.避免從網(wǎng)絡(luò)獲取相關(guān)的文件,這點(diǎn)以nodejs為開(kāi)發(fā)或編譯的項(xiàng)目尤其重要,安裝node的依賴包總是一個(gè)漫長(zhǎng)的過(guò)程,就算有國(guó)內(nèi)的源,一般的項(xiàng)目也需要一兩分鐘的node依賴包,這不符合快速構(gòu)建.
交付 :?在持續(xù)編譯的過(guò)程,使用自動(dòng)化已經(jīng)可以避免大多數(shù)的錯(cuò)誤了.但是還是需要人為介入的系統(tǒng)測(cè)試,畢竟自動(dòng)化的測(cè)試一般只能覆蓋到70%左右.
根據(jù)我們團(tuán)隊(duì)內(nèi)部推廣這種工作方式的效果來(lái)看,持續(xù)集成確實(shí)讓我們工作便利了許多, 每次代碼的構(gòu)建和自動(dòng)化測(cè)試讓我們及時(shí)發(fā)現(xiàn)存在的bug.好的工作模式也需要團(tuán)隊(duì)成員的遵守,團(tuán)隊(duì)成員應(yīng)該積極的擁抱這種工作方式,團(tuán)隊(duì)成員需要做好以下幾點(diǎn).
1.使用版本工具例如git.git有強(qiáng)大的版本回溯,成員每次完成一個(gè)小的功能點(diǎn)進(jìn)行代碼提交.合并到master分支,持續(xù)交付工具應(yīng)該配置為代碼更新觸發(fā).團(tuán)隊(duì)內(nèi)部應(yīng)該等到持續(xù)交付流程結(jié)束之后,確認(rèn)編譯、自動(dòng)化測(cè)試通過(guò)之后方可進(jìn)行下一個(gè)版本的提交,這樣容易定位bug.而不會(huì)導(dǎo)致這次bug影響團(tuán)隊(duì)內(nèi)其他成員的工作.
2.主分支的代碼bug不應(yīng)該存留時(shí)間過(guò)長(zhǎng),避免團(tuán)隊(duì)內(nèi)其他成員合并代碼的時(shí)候引入其他問(wèn)題.
3.測(cè)試驅(qū)動(dòng)開(kāi)發(fā),任何一個(gè)新的功能開(kāi)發(fā)都應(yīng)該先寫好單元測(cè)試腳本,并積極更新自動(dòng)化測(cè)試腳本.并且積極地?fù)肀y(cè)試,雖然你明白這個(gè)測(cè)試不通過(guò)的問(wèn)題并不會(huì)引起很大的系統(tǒng)性問(wèn)題 ,但是還是應(yīng)該進(jìn)行修復(fù)而不是想方設(shè)法的跳過(guò)這個(gè)自動(dòng)化測(cè)試.
4.臨近下班的時(shí)候不要提交代碼,這主要是因?yàn)樽袷氐?點(diǎn).
Docker已經(jīng)越來(lái)越火,CICD和Devops也是Docker一個(gè)重要的場(chǎng)景.在持續(xù)交付中使用Docker有一下優(yōu)點(diǎn).
在持續(xù)集成方面,我們選擇Jenkins.Jenkins是一款開(kāi)源軟件,擁有眾多優(yōu)秀的插件,依靠這些插件,我們可以完成一些周期、繁瑣、復(fù)雜的任務(wù).例如我們今天分享的持續(xù)發(fā)布,雖然Jenkins解決了我們繁瑣復(fù)雜周期性的操作,但是沒(méi)有解決我們?cè)诙喾N環(huán)境下編譯構(gòu)建的需求.而這個(gè)場(chǎng)景正是Docker的強(qiáng)項(xiàng).通過(guò)Jenkins的pipeline我們可以實(shí)現(xiàn)代碼檢出、單元測(cè)試、編譯、構(gòu)建、發(fā)布、測(cè)試等流程的自動(dòng)化,而最終通過(guò)Jenkins的Docker插件將產(chǎn)出物構(gòu)建成鏡像,方便部署到Docker環(huán)境.
持續(xù)集成讓我們新的代碼源源不斷的構(gòu)建成了鏡像,這些鏡像經(jīng)歷了單元測(cè)試,自動(dòng)化測(cè)試,但還沒(méi)有接受過(guò)測(cè)試團(tuán)隊(duì)的嚴(yán)格測(cè)試.Jenkins是一個(gè)強(qiáng)大的持續(xù)集成工具,然而持續(xù)部署并不是Jenkins的強(qiáng)項(xiàng),但是Jenkins擁有很多強(qiáng)大的插件.而且我們持續(xù)集成產(chǎn)出的是鏡像,所以持續(xù)的部署,我們只需要將鏡像運(yùn)行起來(lái),或者利用第三方的容器管理平臺(tái)提供的API進(jìn)行部署.
1.本地部署應(yīng)用到Docker.
本地部署到Docker容器可以使用Jenkins的docker插件,下面會(huì)介紹.
2.部署到遠(yuǎn)程主機(jī)的Docker、Appsoar.
Docker和Appsoar都支持開(kāi)啟API調(diào)用.通過(guò)現(xiàn)有的API我們可以運(yùn)行我們生成鏡像版本.從而達(dá)到持續(xù)的部署最新版本.
3.部署到kubernetes.
kubernetes除了可以通過(guò)API調(diào)用還可以在jenkins中配置kubectl的方式創(chuàng)建或更新deployments.
Docker部署Jenkins的方式簡(jiǎn)單方便,下面我們介紹用Docker的方式運(yùn)行Jenkins.
解鎖的密碼在容器的log中可以查看,或者直接查看jenkins_home指定文件
下面我們創(chuàng)建一個(gè)的Jenkins的Pipeline完成簡(jiǎn)單的cicd流程.
以下是偽代碼,僅提供思路
Jenkins pipeline的腳本語(yǔ)法是groovy的語(yǔ)法,其中docker 、Git是插件提供的能力.代碼的執(zhí)行流程如下:
通過(guò)簡(jiǎn)單的例子,可見(jiàn)Jenkins和Docker的結(jié)合給CICD帶來(lái)了足夠的便利和強(qiáng)大.我們需要準(zhǔn)備的只是一個(gè)編譯的腳本,在編譯腳本中可以使用任何的環(huán)境和任何的版本.
Jenkins的任務(wù)兩個(gè)主要版本.
free style只是一個(gè)自動(dòng)化的腳本,腳本類型為shell.所有的腳本在一臺(tái)機(jī)器上運(yùn)行,需要的環(huán)境需要提前準(zhǔn)備.配置不集中,混亂.但是一般情況下還是夠用的.
pipeline 是jenkins2的版本使用了一個(gè)基于groovy腳本的任務(wù)類型,通過(guò)一系列的stage將構(gòu)建的不同部分組合成一個(gè)pipline.而且配合step可以完成異步操作.因?yàn)榛趃roovy可編程性更加強(qiáng)大,而且腳本可以存放在源碼中,腳本的更改不需要直接到j(luò)enkins中修改.
1.Jenkins的資料較少,官網(wǎng)可以查看的內(nèi)容也不多,一般的需求Jenkins內(nèi)置的pipeline-syntax里面就有常用的命令生成器.可以滿足大多數(shù)需求.
2.在pipeline腳本調(diào)試完成之后應(yīng)該將腳本以文件的形式放在源碼目錄中,這樣子方便修改.和多分支需要編譯的情況下進(jìn)行互相隔離.
3.應(yīng)該多查找下相應(yīng)的插件,而不是使用sh用執(zhí)行腳本的方式來(lái)解決問(wèn)題.
4.應(yīng)該將jenkins_home目錄掛在出來(lái),如果遇上了Jenkins崩潰了可以及時(shí)的恢復(fù)數(shù)據(jù).
5.應(yīng)該新建一個(gè)定時(shí)的pipeline用來(lái)清理生成的鏡像,減少硬盤資源的占用.
6.頁(yè)面新建的pipeline,在頁(yè)面刪除之后,jenkins_home/workspace中對(duì)應(yīng)的項(xiàng)目文件并不會(huì)被刪除.
持續(xù)發(fā)布很多團(tuán)隊(duì)想有這樣的工具達(dá)到這個(gè)效果,有些團(tuán)隊(duì)覺(jué)得不需要.任何工具、流程都需要符合自身團(tuán)隊(duì)的實(shí)際.從我開(kāi)始參與團(tuán)隊(duì)內(nèi)的這個(gè)和持續(xù)發(fā)布有關(guān)的項(xiàng)目,查看了許多資料,結(jié)合團(tuán)隊(duì)項(xiàng)目?jī)?nèi)的實(shí)踐.給出的一些經(jīng)驗(yàn)的和見(jiàn)解和大家一起分享,如有錯(cuò)誤或者建議,歡迎大家及時(shí)溝通.
Q&A
Q1:請(qǐng)問(wèn)Kubernetes怎么結(jié)合Jenkins做持續(xù)集成呢?
A1:部署到Kubernetes.Kubernetes除了可以通過(guò)API調(diào)用還可以在Jenkins中配置kubectl的方式創(chuàng)建或更新deployments.
Q2:必須通過(guò)pipeline才能實(shí)現(xiàn)Jenkins把代碼構(gòu)建成Docker鏡像么?
A2:不一定,使用Docker主要是方便進(jìn)行編譯環(huán)境的隔離,也可以配置好NFS,構(gòu)建完成之后復(fù)制到固定的服務(wù)器上,這個(gè)我們一般叫制品庫(kù).
Q3:Pipeline如何通過(guò)Docker容器部署應(yīng)用到不同的節(jié)點(diǎn)上去?發(fā)布遇到問(wèn)題如何回滾版本的?
A3:Jenkins的能力更多的是做持續(xù)集成(CI)的功能,部署和回滾都需要容器管理平臺(tái)并不是Jenkins的強(qiáng)項(xiàng),特別是回滾單依靠Jenkins很難做到完美的方案.但是部署到不同的Docker的節(jié)點(diǎn)上,可以使用第三方的管理平臺(tái),例如Appsoar和k8s提供的API能力,可以進(jìn)行部署.Jenkins直接調(diào)用curl命令執(zhí)行容器管理平臺(tái)提供的API.
Q4:pipeline的每個(gè)環(huán)節(jié)的報(bào)告如何快速獲取?比如代碼靜態(tài)檢查,工程構(gòu)建,測(cè)試報(bào)告等等.
A4:?http://jenkins:8080/job/clearImages/86/wfapi/,通過(guò)Jenkins這個(gè)API,可以獲取一些狀態(tài)和時(shí)間信息,至于詳細(xì)的代碼靜態(tài)檢查,每種語(yǔ)言都有不同的語(yǔ)法檢查.需要自行配置.當(dāng)然詳細(xì)的需要查看輸出日志.
Q5:關(guān)于測(cè)試驅(qū)動(dòng)開(kāi)發(fā),在開(kāi)發(fā)之前寫好的用例一定要是自動(dòng)化的嗎?為什么?
A5:一個(gè)系統(tǒng)由若干的方法組成,單元測(cè)試就是測(cè)試你寫的方法是否符合你的業(yè)務(wù)要求.所以先寫合理的單元測(cè)試,只要你的方法通過(guò)了這個(gè)單元測(cè)試就表示你寫的這個(gè)方法是正確的,單元測(cè)試代碼是需要開(kāi)發(fā)人員編寫的,每種語(yǔ)言有不同的單元測(cè)試框架例如Nodejs的mocha,Golang 的go test.自動(dòng)化測(cè)試由測(cè)試人員編寫.單元測(cè)試應(yīng)該需要脫離外部因素,不依賴數(shù)據(jù)庫(kù)、不依賴外部API.
Q6:怎么觸發(fā)工作流的?
A6:Jenkins pipeline 提供了三種方式(如果安裝了SCM的插件可能有其他的方式觸發(fā)),進(jìn)入到pipeline的設(shè)置頁(yè)面中的分別有.wbhook(觸發(fā)遠(yuǎn)程構(gòu)建 (例如,使用腳本))、定時(shí)觸發(fā)(Build periodically)、代碼更新觸發(fā)(Poll SCM).
Q8:Jenkins的編譯環(huán)境是怎么處理的,實(shí)際用戶的編譯需求和環(huán)境都不一樣?
A8:用戶需要清楚你使用的編譯環(huán)境的基本情況,例如golang的編譯環(huán)境,容器中的GOPATH是在什么位置.你需要將你的代碼ln到什么目錄才能進(jìn)行編譯,等這些細(xì)節(jié)都是需要用戶提前知曉.
Q9:Jenkins里的有用戶權(quán)限管理嗎,貴公司的CI/CD是怎么實(shí)現(xiàn)用戶隔離的,每個(gè)用戶只能看到自己的項(xiàng)目.
A9:Jenkins當(dāng)中并沒(méi)有用戶權(quán)限.公司在研發(fā)的產(chǎn)品中,有一個(gè)虛擬的概念叫用戶組,對(duì)應(yīng)的是k8s中的一個(gè)或多個(gè)namespaces.管理員將成員用戶添加到這個(gè)用戶組中,組內(nèi)成員創(chuàng)建的資源(pipeline、集群、服務(wù),等)在組內(nèi)是可見(jiàn),用戶組來(lái)進(jìn)行邏輯概念上的隔離
Q10:貴公司Jenkins和Kubernetes是怎么結(jié)合使用的?是什么的部署形式?如何回滾?
A10:我看到很多朋友都提問(wèn)了,Jenkins如何跨主機(jī)部署或者如何部署到Kubernetes集群,如何回滾.Jenkins對(duì)這方面的能力比較弱,僅僅能夠支持kube-api-server的調(diào)用而已,如果完全依靠Jenkins是很難完成需求,所以我們的產(chǎn)品當(dāng)中有一個(gè)專門對(duì)接kubernetes的deploy的模塊,一個(gè)應(yīng)用商店的模塊,一個(gè)封裝了Jenkins的uflow模塊,uflow模塊向應(yīng)用商店獲取模板并根據(jù)當(dāng)前編譯構(gòu)建出來(lái)的鏡像tag號(hào)替換模板,并交付給deploy模塊創(chuàng)建.回滾和升級(jí)都由deploy模塊負(fù)責(zé).這樣各自分開(kāi),各司其職.
Q11:多個(gè)PHP項(xiàng)目,在Docker 應(yīng)用中,需要逐個(gè)拆分嗎?一個(gè)項(xiàng)目對(duì)應(yīng)一個(gè)鏡像管理?還是使用文件夾映射的方式構(gòu)建鏡像?
A11:多個(gè)項(xiàng)目服務(wù)是放在一個(gè)容器中還是分開(kāi)容器中,這個(gè)并沒(méi)有強(qiáng)制的限定.但是建議還是分為多個(gè)容器進(jìn)行部署.Docker的理念就是一個(gè)容器完成一個(gè)單獨(dú)的事情.
Q12:Jenkins PIpeline input指令可以復(fù)雜的參數(shù)化么?
A12:input是一個(gè)比較強(qiáng)大的指令,可以在pipeline的運(yùn)行過(guò)程中確認(rèn)操作,字符輸入,文件上傳等功能.詳細(xì)的可以看下jenkins的pipeline-syntax有使用說(shuō)明和腳本的生成.
Q13:Jenkins自動(dòng)觸發(fā)job到build docker image,自動(dòng)觸發(fā)是怎么實(shí)現(xiàn)的,wedhook 定時(shí)觸發(fā)有沒(méi)遇到過(guò)問(wèn)題?不能正常觸發(fā)的?
A13:自動(dòng)觸發(fā)的原理的原理是,我們?cè)趐ipeline中配置一個(gè)定時(shí)器,這個(gè)定時(shí)器是用cron表達(dá)式表示.例如你設(shè)置了 “* * * * * ”就表示每分鐘檢查一次,那么檢查什么呢,檢查每次提交的ID,例如git的commit ID .只要檢測(cè)到了這個(gè)ID和上一次的不一致就會(huì)觸發(fā)pipeline的構(gòu)建.從目前使用并沒(méi)有出現(xiàn)過(guò)不能觸發(fā)的情況.如果出現(xiàn)了請(qǐng)檢查是否是配置的錯(cuò)誤.
Q14:CD過(guò)程中,重造的輪子和開(kāi)源組件是一個(gè)什么樣的比例?個(gè)人推崇哪個(gè)?
A14:自己重復(fù)造輪子和開(kāi)源組件應(yīng)該如何選擇,這個(gè)是很有意思的一個(gè)問(wèn)題.因?yàn)殚_(kāi)發(fā)者都說(shuō)不要重復(fù)造輪子,這是因?yàn)楹芏噍喿咏?jīng)過(guò)了很多項(xiàng)目考驗(yàn)和眾多開(kāi)發(fā)者提交代碼和fix的bug.這些項(xiàng)目肯定是比自己從頭開(kāi)始造一個(gè)輪子更加有效率而且使用風(fēng)險(xiǎn)低,畢竟所有人都想完成工作上的任務(wù)早點(diǎn)下班.但從個(gè)人發(fā)展來(lái)說(shuō),有些輪子還是值得自己去制造一次的,這樣子你才會(huì)了解到這個(gè)組件的工作原理、底層的東西.所以我個(gè)人的推崇的是,假如你找到了合適接近完美的輪子那就直接用,如果找到了一個(gè)可用但總覺(jué)得用起來(lái)不太爽的組件,那你就把輪子造起來(lái)吧.
文章來(lái)自微信公眾號(hào):DBAplus社群
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/4190.html