原文:BUILDING WITH JENKINS INSIDE AN EPHEMERAL DOCKER CONTAINER
作者:Maxfield Stewart ? ? 譯者:杰微刊兼職翻譯劉曉鵬?
《容器的深入思考》一文告訴大家如何在容器中構(gòu)建一個(gè)項(xiàng)目限匣。今天沈条,我將向大家展示我的團(tuán)隊(duì)當(dāng)前是如何綜合運(yùn)用Jenkins和Docker來(lái)為Riot引擎團(tuán)隊(duì)提供服務(wù)的层释。在最近的博文中谭网,我承諾不就將會(huì)直接討論實(shí)際的salve構(gòu)建和Jenkins配置雄人。但是,從某種意義上講授霸,這是一件主要的事件:如果你沒有一臺(tái)接收salve的Jenkins服務(wù)器里烦,最好的辦法是回過(guò)去看看我以前的博客。
不過(guò)哥艇,在正確的開始本教程之前绝编,我們先討論一下方式和方法。通過(guò)Docker貌踏,有很多種方式來(lái)創(chuàng)建 slaves十饥。即使縮小場(chǎng)景,只使用 Jenkins哩俭,還是有多種選擇绷跑。通過(guò)研究與發(fā)現(xiàn),我覺得有兩種主要的方式你可以采用凡资。從概念上講,我將這兩種模式稱之為“Docker execution”和“Docker ephemeral slave”谬运。
這兩種方式的本質(zhì)區(qū)別是Jenkins如何與構(gòu)建的slave進(jìn)行連接和通信隙赁。在執(zhí)行模式下,Jenkins使用一種傳統(tǒng)的流行方式連接:在虛擬機(jī)或者物理設(shè)備上運(yùn)行一個(gè)客戶端梆暖,這里指的就是一臺(tái)運(yùn)行的Docker主機(jī)伞访。在臨時(shí)模式中,Jenkins直接連接Docker容器轰驳,將其視為一個(gè)構(gòu)建的slave厚掷。這兩者之間的區(qū)別很重要,所以我們花一點(diǎn)時(shí)間來(lái)分解這兩種模式级解。
DOCKER 執(zhí)行模式
在執(zhí)行模式下冒黑,我們?cè)诮Y(jié)構(gòu)上假定slave是一臺(tái)Docker主機(jī),但是把它當(dāng)做一臺(tái)物理機(jī)來(lái)處理勤哗。當(dāng)一個(gè)Jenkins任務(wù)啟動(dòng)時(shí)抡爹,它直接在slave上同步/創(chuàng)建一個(gè)工作目錄,并通過(guò)“docker run”和“docker exec”命令來(lái)轉(zhuǎn)換容器芒划,然后將其掛載到本地的工作空間中冬竟。容器是一個(gè)虛擬暫存空間欧穴,是一個(gè)隔離的環(huán)境。它可以包含所有的自定義版本的工具和二進(jìn)制文件(我們需要對(duì)裝載到容器的源代碼進(jìn)行編譯)泵殴。
當(dāng)一個(gè)構(gòu)建任務(wù)完成時(shí)涮帘,所有二進(jìn)制文件和生成的構(gòu)建歸檔文件將會(huì)發(fā)送到傳統(tǒng)Jenkins工作空間中的slave上。然后笑诅,Jenkins可以安全的關(guān)閉容器焚辅,正常的執(zhí)行后續(xù)的清理工作。
該模式的最佳代表是Cloudbees定制構(gòu)建環(huán)境插件(Cloudbees Custom Build Environment Plugin)苟鸯,該插件是一個(gè)開源插件同蜻,由 Jenkins 源碼庫(kù)的主人維護(hù)。
DOCKER 臨時(shí) Slave 模式
臨時(shí)模式的目的在于利用Docker容器的自主性和隔離性來(lái)擴(kuò)展 Jenkins 的構(gòu)建范圍早处,以滿足在Jenkins上的任何需求湾蔓。相對(duì)于傳統(tǒng)的預(yù)先分配slave數(shù)組或現(xiàn)成的虛擬機(jī),這種模式將容器自身看做是一個(gè)slave砌梆。
當(dāng)Jenkins的執(zhí)行器上有一個(gè)需求時(shí)默责,我們需要轉(zhuǎn)換容器,自動(dòng)地配置Jenkins以便將該容器視為一個(gè)新的slave來(lái)接收咸包,然后執(zhí)行任務(wù)桃序,最后關(guān)閉容器,回收slave烂瘫。當(dāng)然這種模式比執(zhí)行模式更復(fù)雜媒熊。
這種方式有幾個(gè)相互競(jìng)爭(zhēng)的插件,這些插件通常都是以如何維護(hù)和構(gòu)建Docker云為中心坟比。迄今為止芦鳍,這種插件有Kubernetes,Mesos以及“純”Docker方式葛账。
如何選擇模式柠衅?
兩種模式都能有效的解決問題。在Riot籍琳,我們感興趣的是為特定的目標(biāo)獲取分配盒子和“執(zhí)行器”的方式菲宴,所以臨時(shí)模型對(duì)我們有很強(qiáng)的吸引力。我們喜歡用一個(gè)容器來(lái)代表整個(gè)slave的想法趋急。因此喝峦,我們使用Docker Plugin 來(lái)完成我們的目標(biāo)。
隨著時(shí)間的推移宣谈,我們很高興當(dāng)初的選擇愈犹。Docker Plugin的主開發(fā)者(KostyaSha)對(duì)該插件的維護(hù)非常活躍,經(jīng)常更新漩怎,并且有很強(qiáng)大的社區(qū)勋颖。他負(fù)責(zé)響應(yīng)問題,并在GitHub repo 提供了清晰的路線圖勋锤。沒有他的工作饭玲,我不可能完成這篇文章中提供的教程,該教程是基于 0.16 版本插件的叁执。
此外請(qǐng)注意茄厘,KostyaSha最近將“Docker Plugin”分出來(lái)一個(gè)新的倉(cāng)庫(kù)“Yet Another Docker Plugin”進(jìn)行繼續(xù)開發(fā)。由于我們現(xiàn)在的生產(chǎn)環(huán)境正在使用的插件是“Docker Plugin”谈宛,所以在本文中選擇該插件進(jìn)行分析次哈。
在以后,我們可能會(huì)改變我們的想法吆录。我們盡量保證靈活性窑滞,以便在有更好的解決方案時(shí)能夠方便的進(jìn)行轉(zhuǎn)換。我們采取的方式也受到過(guò)教訓(xùn)-在本教程最后我會(huì)對(duì)它們進(jìn)行描述恢筝。
教程
這是我寫的最長(zhǎng)的教程哀卫。所以我決定在這只保存鏈接以節(jié)省空間(將實(shí)現(xiàn)與方案進(jìn)行分離)。如果你已經(jīng)清楚了之前的文章撬槽,該教材只需要花費(fèi)30-45分鐘左右的時(shí)間就可完成此改。你可以從這獲取到完整的教程:
另外,如果你想跳過(guò)結(jié)構(gòu)部分侄柔,盡快開始并運(yùn)行起來(lái)共啃,你可以從這獲取到完整的教程,然后按照 README 中的說(shuō)明進(jìn)行操作:
https://github.com/maxfields2000/dockerjenkins_tutorial/tree/master/tutorial_07
經(jīng)驗(yàn)教訓(xùn)
運(yùn)營(yíng)這個(gè)平臺(tái)有著諸多其自身獨(dú)特的挑戰(zhàn)勋拟。請(qǐng)記住這個(gè)簡(jiǎn)短的列表勋磕,希望能幫助你節(jié)省時(shí)間和精力:
運(yùn)營(yíng)一個(gè)大規(guī)模的 DOCKERHOSTS 并不是一個(gè)簡(jiǎn)單的任務(wù)。
磁盤空間是一個(gè)大問題敢靡。Docker鏡像很消耗空間。每個(gè)運(yùn)行的容器也要耗費(fèi)空間苦银。有時(shí)候啸胧,容器掛了也還會(huì)占用空間。有的團(tuán)隊(duì)使用卷來(lái)創(chuàng)建slave幔虏,這需要耗費(fèi)更多的空間纺念。
在Docker主機(jī)上監(jiān)控磁盤空間是必不可少的,不要等到磁盤消耗完的時(shí)候再去處理想括,要及時(shí)的監(jiān)控并處理陷谱。
清理鏡像和容器,就像垃圾回收一樣。
每次一個(gè)新的鏡像推送到Docker主機(jī)烟逊,都會(huì)留下“懸浮”的未使用層渣窜,清理這些空間應(yīng)該是日常的操作,否則磁盤空間就會(huì)成為問題宪躯。
容器的slave有時(shí)無(wú)法停止或無(wú)法清理乔宿,關(guān)注“退出”和“死亡”的容器是保證Docker主機(jī)清潔必不可少的一部分。
增加新的鏡像/SLAVE 到 DOCKERHOSTS 隊(duì)列是一個(gè)很耗時(shí)的操作访雪。
最初详瑞,要求工程師必須將他們的鏡像在 Jenkins 中進(jìn)行配置。很快我們發(fā)現(xiàn)這個(gè)過(guò)程是一個(gè)不必要的障礙臣缀。根據(jù)我們的經(jīng)驗(yàn)坝橡,在早期的開發(fā)中,工程團(tuán)隊(duì)平均每周需要對(duì)他們的Dockerfile做多次修改精置。
我們創(chuàng)建一個(gè)稱之為“Harbormaster”的工具计寇,該工具通過(guò) Groovy 的API,能夠自動(dòng)的驗(yàn)證工程師提供的鏡像氯窍,并自動(dòng)的配置 Jenkins饲常。Harbormaster 通過(guò)一組核心的標(biāo)準(zhǔn)來(lái)測(cè)試每個(gè)鏡像,并驗(yàn)證salve是否正常工作狼讨。然后生成一份測(cè)試報(bào)告并自動(dòng)配置Jenkins贝淤。
關(guān)于 Harbormaster 如何工作的討論可能會(huì)導(dǎo)致本文過(guò)長(zhǎng)。我將在以后的博客對(duì)其進(jìn)行闡述政供。
風(fēng)險(xiǎn)監(jiān)控室是必不可少的
關(guān)于如何監(jiān)控 Jenkins 和Docker Swarm播聪,我們也還在不斷的成長(zhǎng)中。Docker Cloud 的監(jiān)控藝術(shù)是發(fā)展過(guò)程中的永恒主題布隔,并且當(dāng)這個(gè)云是一個(gè)構(gòu)建場(chǎng)景而不是應(yīng)用場(chǎng)景時(shí)离陶,還會(huì)呈現(xiàn)出一種獨(dú)特的扭曲狀態(tài)。
正如Harbormaster衅檀,在這討論監(jiān)控也會(huì)使得本文太長(zhǎng)招刨。同樣,我會(huì)在以后的博客中更多的討論生產(chǎn)環(huán)境下的監(jiān)控問題哀军。
JENKINS的審計(jì)可能會(huì)咬到你
曾經(jīng)沉眶,由于 Jenkins 的崩潰導(dǎo)致磁盤消耗完的問題,導(dǎo)致我們工作到半夜杉适。結(jié)果是因?yàn)椤皠?chuàng)建/銷毀”構(gòu)建的slave時(shí)谎倔,產(chǎn)生了 100,000 個(gè)微小的日志文件。Jenkins保存了所有的創(chuàng)建和銷毀slave時(shí)的審計(jì)文件猿推;一定要注意片习,否則你會(huì)死的很難看。
當(dāng)然還有更多的經(jīng)驗(yàn)教訓(xùn)。在以后的博客中我還繼續(xù)會(huì)討論我們是如何處理某些問題的藕咏,所以有問題就趕緊問吧状知,不要猶豫!
你的生產(chǎn)環(huán)境系統(tǒng)和我們的研究結(jié)果
隨著本教程的結(jié)束侈离,你應(yīng)該已經(jīng)有了一個(gè)完整功能Docker Jenkins 沙盒试幽。在創(chuàng)建過(guò)程中你會(huì)遇到一些困難,在生產(chǎn)環(huán)境中你也需要做幾件事情卦碾。
1.使用Docker Plugin 配置你生產(chǎn)環(huán)境的 Jenkins 主服務(wù)器铺坞,正如你在上述教程中做的一樣(安裝插件)。
2.啟動(dòng)一個(gè)“生產(chǎn)環(huán)境”的Docker主機(jī)洲胖。這可能有點(diǎn)超出了本教程的范圍济榨。我們的流水線團(tuán)隊(duì)使用 Centos 虛擬機(jī)來(lái)運(yùn)行 VSphere,不過(guò)你也可以使用 AWS 的實(shí)例或物理機(jī)绿映,任何你想要的有效的Docker主機(jī)都行擒滑。這就是Docker的強(qiáng)大之處。
3.如果在構(gòu)建環(huán)境的Docker主機(jī)中叉弦,沒有使用 TLS 安全機(jī)制(在安全環(huán)境中并不少見)丐一,確保在設(shè)置中移除“https”和“Docker cert path”。
4.如果你正在使用 TLS淹冰,確保在 Jenkins 中配置生產(chǎn)環(huán)境的證書库车。
5.確保你構(gòu)建的slave鏡像是生產(chǎn)環(huán)境下的Dockerhost所能到達(dá)的。在 Riot樱拴,我們使用一個(gè)中央鏡像倉(cāng)庫(kù)柠衍。
很多東西都涉及到安裝,所以晶乔,請(qǐng)不猶豫珍坊,有什么問題就問,并提供必要的點(diǎn)正罢。
對(duì)于我們來(lái)說(shuō)阵漏,這不是一個(gè)“沙盒”或“玩耍”的設(shè)置翻具。這個(gè)教程中袱饭,列出的只是我們?cè)诰€環(huán)境中改變的一個(gè)組件。我們生產(chǎn)環(huán)境的Dockerhost實(shí)際上是一個(gè)Docker Swarm 應(yīng)用呛占,由 10 臺(tái)Dockerhost機(jī)器支撐。下面這些圖標(biāo)展示我們現(xiàn)在(發(fā)布本文的時(shí)候)是如何設(shè)置這些東西的
抽象結(jié)構(gòu)
物理結(jié)構(gòu)
這是來(lái)自我們生產(chǎn)系統(tǒng)中的某些統(tǒng)計(jì)數(shù)據(jù)
Jenkins 統(tǒng)計(jì)數(shù)據(jù):
Jenkins 統(tǒng)計(jì)數(shù)據(jù)細(xì)節(jié)
平均隊(duì)列大信城鳌:20-30
預(yù)備執(zhí)行器:~650
平均使用的執(zhí)行器:30-40
構(gòu)建節(jié)點(diǎn)的總數(shù)量:~80
每小時(shí)的平均任務(wù)數(shù):~600
DockerJenkins 統(tǒng)計(jì)數(shù)據(jù)
DockerJenkins 統(tǒng)計(jì)數(shù)據(jù)細(xì)節(jié)
平均隊(duì)列大辛缆恰:3
預(yù)備執(zhí)行器:20(為構(gòu)建流程控制)
平均使用的執(zhí)行器:3
任意時(shí)間的平均節(jié)點(diǎn)數(shù):5
每小時(shí)的平均任務(wù)數(shù):50
去年初年初,我們將系統(tǒng)部署在Docker很早的版本上(Docker 1.2),Docker Plugin 也是的版本(.8)帜篇,穩(wěn)定性是當(dāng)初關(guān)注一個(gè)核心問題糙捺。不過(guò)現(xiàn)在的版本(Docker 1.10 + Docker Plugin 0.16),我非常相信笙隙,就我們的需求而言洪灯,它是足夠穩(wěn)定的。在這一年中竟痰,我們一直在使用它們签钩,我們從少量的構(gòu)建任務(wù)和幾個(gè)早期的使用團(tuán)隊(duì)發(fā)展到現(xiàn)在,無(wú)論是任務(wù)數(shù)還是團(tuán)隊(duì)數(shù)都有了巨大的增加坏快。很明顯铅檩,一旦我們有機(jī)會(huì)進(jìn)行完整的測(cè)試,我們就會(huì)遷移到新的插件“Yet Another Docker Plugin”上莽鸿。
事實(shí)上昧旨,我們的Dockerized Jenkins平臺(tái)現(xiàn)在構(gòu)建的任務(wù),大概只占我們整個(gè) Jenkins 平臺(tái)所支撐的全部任務(wù)(超過(guò)4000)的25%祥得。網(wǎng)絡(luò)新構(gòu)建任務(wù)創(chuàng)建在傳統(tǒng)Jenkins環(huán)境中的幾乎為0兔沃,大部分新創(chuàng)建的任務(wù)都在我們的Docker平臺(tái)上。原因如下:
1级及、引擎團(tuán)隊(duì)通過(guò)自定義Dockerfiles可以完全控制他們的構(gòu)建環(huán)境乒疏。
2、通過(guò)Docker创千,可以將他們部署的構(gòu)建環(huán)境復(fù)制到本地缰雇,這樣那些“構(gòu)建環(huán)境”就可以很容易在本地進(jìn)行測(cè)試。
3追驴、團(tuán)隊(duì)不在需要“系統(tǒng)管理員”來(lái)構(gòu)建虛擬機(jī)或其他環(huán)境械哟,這些權(quán)限“放手”到了每個(gè)人手里。
結(jié)論
2015年8月殿雪,當(dāng)我開始這一系列博客的寫作之旅時(shí)暇咆,我們已經(jīng)有了一個(gè)功能性的原型。八個(gè)月以后丙曙,博客幾乎趕上了我們當(dāng)前的進(jìn)度爸业,缺乏監(jiān)控和擴(kuò)展。
在這個(gè)點(diǎn)上亏镰,你應(yīng)該對(duì)Docker基礎(chǔ)有一個(gè)很堅(jiān)實(shí)的入門扯旷,并且知道一些關(guān)于Docker的擴(kuò)展和安全問題,這些都通過(guò)Jekins的真實(shí)應(yīng)用場(chǎng)景演示過(guò)索抓。另一方面钧忽,你應(yīng)該有一個(gè)功能性配置文件毯炮,用于配置一個(gè)完整的Jekins測(cè)試環(huán)境,并通過(guò)它來(lái)運(yùn)行你本地的Docker Toolbox Dockerhost耸黑,還包括建立自己的構(gòu)建slave的能力桃煎。這幾乎就是“盒子容器中的Jenkins”,在以后的博客中大刊,我將會(huì)更深入的挖掘這個(gè)生態(tài)系統(tǒng)为迈,分析我們創(chuàng)建的工具、API以及監(jiān)控缺菌。
我真心希望你能覺得這些東西是有用的葫辐。我們收到的反饋也非常棒,我很喜歡社區(qū)的這種熱情男翰。如果你能在下面發(fā)表評(píng)論另患,我將會(huì)非常感激!
所有有效的文件都在我公開的Github上蛾绎;這里所有的一切僅僅是開源的魔法昆箕!在這里,可以毫不猶豫的發(fā)起問題租冠,提出需求等鹏倘。