基于 Docker、Kubernetes 實(shí)現(xiàn)高效可靠的規(guī)?;?CI/CD 流水線的搭建

大數(shù)據(jù)

作者:?jihong10102006

高效可靠的CI/CD流水線是一個(gè)IT組織實(shí)現(xiàn)軟件服務(wù)快速交付的基礎(chǔ),現(xiàn)如今大量企業(yè)采用jenkins集群來搭建其交付流水線。然而,如何管理大量Jenkins Slave的差異化?如何簡單快速實(shí)現(xiàn)Jenkins能力的橫向擴(kuò)展?如何實(shí)現(xiàn)流水線的高可用?如何有效利用閑置的Jenkins Slave資源?上述這些問題一直困攏著集群管理員,近兩年隨著虛擬化技術(shù)突飛猛進(jìn)的發(fā)展,Docker, Kubernetes 等現(xiàn)代化工具徹底顛覆了交付團(tuán)隊(duì)的交付流程,同時(shí)也為CI/CD流程水線的搭建與管理提供了全新思路。

Setup

目前流行的CI工具很多,鑒于本文討論CI/CD流水線在企業(yè)中的應(yīng)用,考慮到企業(yè)不會(huì)有意愿將源代碼的訪問權(quán)開放給第三方,像Travis CI等這些基于SaaS的CI工具自然被pass,由于Jenkins在CI領(lǐng)域的主導(dǎo)性地位,所以本文的CI工具只涉及Jenkins。另外,本文默認(rèn)您對Jenkins, Docker, Kubernetes 等工具有一些基礎(chǔ)的了解。

持續(xù)交付流水線簡介

簡單介紹一下持續(xù)交付流水線,如下圖所示,簡單來說流水線工作流程是這樣的,當(dāng)代碼庫有代碼變更的時(shí)候持續(xù)集成服務(wù)器(Jenkins)會(huì)監(jiān)聽到代碼變更并自動(dòng)觸發(fā)第一個(gè)階段 — 持續(xù)集成階段,這個(gè)階段做的事情是自動(dòng)構(gòu)建,單元測試,靜態(tài)代碼分析以及生成報(bào)告。如果所有步驟都如預(yù)期成功通過的話會(huì)自動(dòng)進(jìn)入下一個(gè)階段 — 自動(dòng)化測試階段,在跑自動(dòng)化測試套件之前,首先要把成功通過第一階段的產(chǎn)出物(artifact), 如果選擇java做為開發(fā)語言的話就是生成的war包,ruby的話就是gem文件,部署到測試服務(wù)器上,部署完成之后觸發(fā)自動(dòng)化測試套件,包括驗(yàn)收測試,容量測試,性能測試等會(huì)自動(dòng)執(zhí)行,如果所有測試用例都順利通過(有些公司還需要做一些手工測試如探索性測試等)的話,那么這個(gè)版本就會(huì)被標(biāo)記成一個(gè)可發(fā)布的侯選版本。一旦業(yè)務(wù)需要,就會(huì)通過一鍵部署的方式將相應(yīng)的侯選版本發(fā)布到生產(chǎn)環(huán)境上去。如果你想更多的了解持續(xù)交付相關(guān)的知識請閱讀David Farley and Jez Humble的名著《Continues Delivery》。

大數(shù)據(jù)

踐與痛點(diǎn)

上述這個(gè)過程實(shí)現(xiàn)起來需要這樣做,首先需要把上圖中各個(gè)階段的工作腳本化,說具體一點(diǎn)就是需要寫一個(gè)構(gòu)建腳本來完成編譯,單元測試,靜態(tài)代碼分析,生成報(bào)告等步驟,從而完成持續(xù)集成階段的工作,然后是自動(dòng)化測試腳本,這個(gè)腳本可以觸發(fā)自動(dòng)化測試套件并生成相關(guān)報(bào)告,最后需要寫一個(gè)部署腳本,用于將持續(xù)集成階段的產(chǎn)出物部署到測試環(huán)境上(當(dāng)然最后的發(fā)布階段也會(huì)重用這個(gè)腳本),這里需要注意的是要確保部署都是可重復(fù)的,重復(fù)部署同一個(gè)產(chǎn)出物N次的效果與只部署一次的效果相同,也就是大家常說的冪等。接下來就輪到Jenkins出場了,首先我們需要配置一下Jenkins來監(jiān)聽代碼庫的變更,這就意味著只要有代碼遷入就會(huì)觸發(fā)相對應(yīng)的流水線,然后我們用Jenkins job或pipeline將這幾個(gè)階段的腳本串聯(lián)起來(下圖是以job為例),這樣一個(gè)簡單的CI/CD流水線就搭建完成了。

大數(shù)據(jù)

如上圖所示,每一個(gè)Job負(fù)責(zé)運(yùn)行某一階段的腳本,可以簡單類比為Job1運(yùn)行持續(xù)集成階段的腳本將源代碼從代碼庫中遷出,編譯,單元測試,靜態(tài)代碼分析以及生成報(bào)告,Job2首先將持續(xù)集成階段的產(chǎn)出物部署到測試環(huán)境并運(yùn)行自動(dòng)化測試套件,生成報(bào)告并標(biāo)記產(chǎn)出物,Job3用于按需發(fā)布。每個(gè)Job所運(yùn)行的腳本依賴的語言或運(yùn)行環(huán)境會(huì)有所不同,可以通過label方式選擇到相應(yīng)的Slave上運(yùn)行。

但在企業(yè)級大規(guī)模的應(yīng)用CI/CD流水線時(shí),由于企業(yè)中多團(tuán)隊(duì)多產(chǎn)品的存在,不同的團(tuán)隊(duì)會(huì)根據(jù)產(chǎn)品自身的特點(diǎn)來選擇不同的技術(shù)實(shí)現(xiàn)方式,這就意味著產(chǎn)品實(shí)現(xiàn)語言會(huì)有很多種,比如java, C#, ruby, python, nodejs …那么相對應(yīng)的CI/CD流水線就需要提供所有語言的編譯環(huán)境并安裝相關(guān)的依賴包,當(dāng)然為了減少依賴,避免沖突以及更好的管理這些編譯環(huán)境聰明的管理員會(huì)選擇讓每一個(gè)slave只能運(yùn)行特定編程語言的Job, 如下圖所示:

大數(shù)據(jù)

上圖這個(gè)Jenkins集群Maser只用來調(diào)度和收集log,所有的Job都會(huì)由Master根據(jù)不同的label導(dǎo)流到對應(yīng)的Slave上運(yùn)行。這種集群的實(shí)現(xiàn)方式是我們在VM時(shí)代不得已的選擇,雖然能解決大部分問題,但也帶來了很多困擾。

單點(diǎn)依賴 Jenkins Master成為單點(diǎn),一旦Jenkins Master down機(jī),那將是災(zāi)難性的,整個(gè)CI/CD流水線都將處于不可用的狀態(tài)。不易維護(hù) 大量差異化的Jenkins Slave管理起來難度很大,由于差異化的存在,維護(hù)升級幾乎都需要手動(dòng)完成,人力成本投入很高。不易擴(kuò)展 舉個(gè)例子,我們發(fā)現(xiàn)流水線對Java7這個(gè)Slave發(fā)出的請求量比較大,經(jīng)常出現(xiàn)排隊(duì)現(xiàn)像。為了緩解這種情況,管理員需要增加一個(gè)可以編譯Java7應(yīng)用的Slave,那么管理員需要怎么做呢?首先需要準(zhǔn)備一臺VM,然后安裝java7以及所有依賴的軟件包,最后配置Slave相關(guān)信息label等并將新安裝好的Slave注冊到Master,基本上都需要人為干預(yù),擴(kuò)展起來非常不方便。資源浪費(fèi) 每一臺Jenkins Slave Server都是一臺實(shí)實(shí)在在運(yùn)行的VM, 當(dāng)Slave Sever空閑時(shí)也不能將它所占用的資源釋放,因?yàn)殡S時(shí)可能需要這個(gè)Slave完成相關(guān)的Job。

解決痛點(diǎn)

下面我們來看一下虛擬化技術(shù)帶來了的福音,下圖是一個(gè)基于Kubernetes, Docker搭建起來的Jenkins集群,為了避免混淆我略去了Kubernetes集群中的Master node。我們看到Jenkins Mater以Docker container的形式運(yùn)行在Kubernetes一個(gè)Node上并將所有Jenkins相關(guān)數(shù)據(jù)存儲(chǔ)到一個(gè)volume中,Jenkins Slave也以Docker container的形式運(yùn)行在各個(gè)Node中,之所以用虛線來表現(xiàn)Slave是因?yàn)镾lave不是一直存在的,它會(huì)被動(dòng)態(tài)的按需創(chuàng)建并自動(dòng)刪除。簡單介紹一下這種動(dòng)態(tài)創(chuàng)建注冊Slave的方式,它的工作流程是,當(dāng)Jenkins Master收到一個(gè)build的請求時(shí),會(huì)用按照label的要求動(dòng)態(tài)的創(chuàng)建一個(gè)運(yùn)行在Docker container中的Jenkins Slave并注冊到Master上, 然后運(yùn)行相應(yīng)的Job,當(dāng)Job運(yùn)行完成后這個(gè)Slave會(huì)被注銷,所在的Docker container也會(huì)被自動(dòng)刪除。

大數(shù)據(jù)

這種基于Docker, Kubernetes搭建的CI/CD流水線給Jenkins集群帶來了諸多益處:

高可用 Jenkins Master被部署在Kubernetes集群上,一旦container運(yùn)行異常意外退出,那么Kubernetes會(huì)自動(dòng)用相同的Docker image幫我們從新起動(dòng)一個(gè)新的Jenkins,并將volume attach給新創(chuàng)建的Docker container,從而保證不會(huì)丟失任何數(shù)據(jù),實(shí)現(xiàn)了Jenkins集群的高可用性。自動(dòng)伸縮 由于每一次運(yùn)行Job時(shí),Jenkins Master都會(huì)動(dòng)態(tài)創(chuàng)建一個(gè)Jenkins slave,Job完成之后Slave會(huì)被注銷所在的Docker container也會(huì)被自動(dòng)刪除,所占用的資源就會(huì)被自動(dòng)釋放。也就是說當(dāng)同時(shí)請求的Job數(shù)量越多,生成的Slave container就會(huì)越多,占用的資源也就越多,反之亦然,而且這種動(dòng)態(tài)伸縮是完全不需要人為干預(yù)的。完全隔離 由于每一次運(yùn)行Job都是在一個(gè)全新的Jenkins slave中運(yùn)行,避免了同時(shí)運(yùn)行的Job與Job之間發(fā)生沖突的可能性。容易維護(hù) 對比之前每一個(gè)Jenkins Slave是一臺固定VM的做法,以這種方式搭建的集群維護(hù)的不再是固定的VM而是創(chuàng)建動(dòng)態(tài)Slave所需要的Docker image,我們可以很容易通過Docker File來build適用于我們自已的Docker image并將它們存儲(chǔ)在私有的Docker registry中,非常易于維護(hù)。容易擴(kuò)展 當(dāng)我們發(fā)現(xiàn)Jenkins的Queue中存在大量等待執(zhí)行的Job是因?yàn)閗ubernetes集群的資源不足時(shí),能夠很容易的初始化一個(gè)kubernetes node并將它添加到集群中來,實(shí)現(xiàn)橫向擴(kuò)展非常的方便。

簡單實(shí)現(xiàn)

下面我們來完成一個(gè)簡單的實(shí)現(xiàn):

1、首先你需要安裝一個(gè)Kubernetes cluster,請參考https://kubernetes.io/docs/setup/ Kubernetes安裝完成之后,首先需要用下面兩條命令和文件部署一個(gè)Jenkins到Kubernetes集群:
代碼?

kubectl?create?-f?jenkins-deployment.yamlkybectl?create?-f?jenkins-service.yaml

大數(shù)據(jù)

tip: 標(biāo)紅的部分很重要,開放8080端口是用來訪問Jenkins web portal用的;而動(dòng)態(tài)創(chuàng)建的Jenkins slave會(huì)默認(rèn)通過50000(可修改)端口與master建立連接。
檢查jenkins安裝運(yùn)行情況:

大數(shù)據(jù)

2、查看Jenkins log,用管理員密碼登錄Jenkins并安裝Kubernetes plugin。

3、 配置Kubernetes cloud

Manage Jenkins/Configure System/ Add a new cloud/ Kubernetes:

大數(shù)據(jù)

Add pod template/Kubernetes Pod Template:

大數(shù)據(jù)

點(diǎn)擊Save之后大功告成。

牛刀小試

下面我們來測試一下這個(gè)動(dòng)態(tài)注冊Slave的Jenkins集群是否工作正常,首先登錄Jenkins創(chuàng)建一個(gè)簡單的free style job,指定這個(gè)Job只能在Label為“jnlp”的agent上運(yùn)行。點(diǎn)擊build now,你會(huì)發(fā)現(xiàn)奇跡發(fā)生了,原來沒有注冊任何Slave的Jenkins動(dòng)態(tài)的創(chuàng)建一個(gè)Slave并注冊到Master上,然后運(yùn)行相應(yīng)的Job,當(dāng)Job運(yùn)行結(jié)束后這個(gè)Slave被自動(dòng)清除了。

大數(shù)據(jù)

PS:這只是一個(gè)簡單的實(shí)現(xiàn),在企業(yè)的實(shí)踐中,我們需要不同的build環(huán)境,需要我們基于jenkinsci/jnlp-slave這個(gè)Image構(gòu)建我們自己的Jenkins slave Image并保存到私有的Registry中,相對應(yīng)的Kubernetes需要從私有Registry拉取Image。

極客網(wǎng)企業(yè)會(huì)員

免責(zé)聲明:本網(wǎng)站內(nèi)容主要來自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請進(jìn)一步核實(shí),并對任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁或鏈接內(nèi)容可能涉嫌侵犯其知識產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書面權(quán)利通知或不實(shí)情況說明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開相關(guān)鏈接。

2017-10-26
基于 Docker、Kubernetes 實(shí)現(xiàn)高效可靠的規(guī)模化 CI/CD 流水線的搭建
作者:?jihong10102006 高效可靠的CI CD流水線是一個(gè)IT組織實(shí)現(xiàn)軟件服務(wù)快速交付的基礎(chǔ),現(xiàn)如今大量企業(yè)采用jenkins集群來搭建其交付流水

長按掃碼 閱讀全文