天天看點

高效運維之Docker持續部署圖文詳解前言

關于docker的文章鋪天蓋地,但精品文章往往翻譯居多。都說docker天生适合持續內建/持續部署,但同樣,可落地、實際可操作性的文章也很少見。

基于這些情況,雖然我們專欄定位為運維管理性文字,但本篇是個特例,實操性的案例講解——java項目如何通過docker實作持續部署(隻需簡單四步),即:

開發同學通過git push上傳代碼,經git和jenkins配合,自動完成程式部署、釋出,全程無需運維人員參與。

這是一種真正的容器級的實作,這個帶來的好處,不僅僅是效率的提升,更是一種<b>變革</b>:

開發人員第一次真正為自己的代碼負責——終于可以跳過運維和測試部門,自主維護運作環境(首先是測試/開發環境)。

難者不會,會者不難。通過簡單的4個配置,即可優雅地實作持續部署。本文依慣例放上目錄,請享用:

持續部署的技術思路

效果展示

配置git和jenkins關聯

配置jenkins自動更新代碼

效果圖文詳解

faq

好吧,我們正式開始。

在本例中,假設我們java項目的名稱為hello。簡要的技術思路如下。

高效運維之Docker持續部署圖文詳解前言

本案例中假設代碼托管在git.oschina.com上,jenkins和docker registry(類似于yum源)各運作在一個docker容器中。java項目自己也單獨運作在一個叫hello的容器中。

本文采取的持續部署方案,是從私有的docker registry拉取代碼,然後通過重建image來實作。這裡<b>jenkins處于中心位置</b>。就像長臂猿,在接收到git的請求後,通過遠端調用伺服器shell腳本,完成幾乎所有功能。

另外,有些變通的方案,把代碼放在主控端上,讓容器通過卷組映射來讀取。這種方法不建議的原因是,<b>将代碼拆分出容器,這違背了docker的集裝箱原則:</b>

這也導緻裝卸複雜度增加。從貨運勞工角度考慮,整體才是最經濟的。這樣,也才能實作真正意義的容器級遷移。

或者說,<b>容器時代,抛棄過去檔案分發的思想,才是正途</b>。本文最後的問答環節對此有更多闡述。

容器即程序。我們采用上述方案做docker持續部署的原因和意義,也在于此。<b>容器的生命周期,應該遠遠短于虛拟機,容器出現問題,應該是立即殺掉,而不是試圖恢複。</b>

<b></b>

本文最後實作的效果,究竟有多驚豔呢?且看如下的示範。

我們以時間戳來簡潔、顯式的表述程式更新情況。

高效運維之Docker持續部署圖文詳解前言

本例中,我們把首頁的時間戳從201506181750,修改為201506191410(見如下)。

高效運維之Docker持續部署圖文詳解前言

順序執行如下操作,輸入正确的git賬号密碼。

高效運維之Docker持續部署圖文詳解前言

然後呢?

然後什麼都不用做了。端杯茶(如果不喜歡咖啡的話),靜靜地等待自動部署的發生, 旁觀一系列被自動觸發的過程,機器人似的運轉起來(請容稍候再加以描述)。

為什麼需要3~5分鐘?隻是因為本案例中的java項目,需要從國外download maven程式包,以供jenkins調用和編譯java。正式應用環境中,可以把maven源放在國内或機房。如果僅僅需要對php項目做持續部署,那就更快捷了。

在靜靜地等待幾分鐘後,新的代碼确實已經自動部署完畢。

高效運維之Docker持續部署圖文詳解前言

那麼,這一切怎麼實作的呢?很複雜麼?不然。隻要按照如下幾步,便可快速實作哦。

這個過程主要分為如下三步。

jenkins中建立項目java-app,并配置從git拉取程式代碼。具體如下:

高效運維之Docker持續部署圖文詳解前言

jenkins中配置token,以供git遠端調用時使用。

高效運維之Docker持續部署圖文詳解前言

怎麼讓git在接收到使用者更新的代碼後,把消息和任務傳遞給jenkins呢?這借助于git的hook功能,配置起來也非常簡單,如下

高效運維之Docker持續部署圖文詳解前言

jenkins的主要工作是配置“遠端建構”。在接收到git傳遞過來的消息後,觸發這個遠端建構(到目标伺服器),按照預定義的任務清單,執行一系列的工作,重建容器等。詳見如下:

高效運維之Docker持續部署圖文詳解前言

我們把其中最關鍵的shell腳本内容摘抄出來。這些docker相關操作,在第1部分“技術思路”已經提及,不再贅述。

高效運維之Docker持續部署圖文詳解前言

在2.3這個章節中,我們當時的操作如下,這個目的是向git送出更新代碼。

高效運維之Docker持續部署圖文詳解前言

當時并沒有細說後續發生的事情,既然上面已經說清楚了原理,那我們就可以接下來說說實際發生的事情啦。

這裡貌似整個過程已經完成并順利退出。其實,背景的工作才剛剛開始哦。

高效運維之Docker持續部署圖文詳解前言

這時會觸發git伺服器向相應的jenkins伺服器發出一個操作請求,此工作太過迅速,也沒啥好說的,我們接下來看jenkins都幹啥子了。

如下這個自動運轉的過程,讓我們有些許成就感,值得端杯咖啡(如果不喜歡茶的話),靜靜觀賞。

<b>1)jenkins會自動”冒出來”一個建構任務。</b>

高效運維之Docker持續部署圖文詳解前言

<b>2)我們點進來,看看具體記錄檔。是的,正在接受來自git的任務。</b>

高效運維之Docker持續部署圖文詳解前言

<b>3)下載下傳maven相關的軟體包(就是這個過程慢)。</b>

高效運維之Docker持續部署圖文詳解前言

<b>4)下載下傳完成後,就開始利用maven build 新的hello項目包。</b>

高效運維之Docker持續部署圖文詳解前言

<b>5)然後重建maven容器,建構新的image并push到docker私有庫中。</b>

高效運維之Docker持續部署圖文詳解前言

<b>6)最後,重新把docker容器拉起來。這樣,又新生了。呵呵</b>

高效運維之Docker持續部署圖文詳解前言

問題1:采用這麼相對複雜的辦法(而不是把更新代碼放在主控端然後卷組映射),是因為項目基于java麼;是否php項目就可以采用更新代碼放在主控端然後卷組映射這種方式?

回答1:将代碼拆分出容器,違背了集裝箱原則。導緻裝卸複雜度增加。從貨運勞工角度考慮,整體才是最經濟的。一切版本化。抛棄過去的檔案分發。這是正途。至于檔案大小,大的war包也就50m或100m,在現有網絡下不成問題,性能問題最好優化。另外建議關注docker 2 docker,p2p傳輸。

問題2:如果整體代碼超過500m或者1g以上,整體集裝箱是否就不太好了?如果容器與代碼分離,鏡像就100m左右(2層,base+服務),然後代碼的話,是放到共享存儲裡,每個代碼有更新,比如svn的代碼,可以直接在共享存儲裡進行svn update就可以控制版本

回答2:如果你的代碼500m,那隻能說明業務開發該打闆子了。

問題3:如果測試環境使用您提供的完整集裝箱服務還行,但在生産環境,叢集裡運作docker做應用,如果每個容器都是有完整的代碼,是否有點臃腫,不如每個叢集節點裡就運作基礎服務鏡像,通過卷組功能綁定共享存儲裡的代碼,加上crontab、python和shell腳本,這樣每次代碼更新就1次就行了。

回答3:環境一緻性,在過去從來沒有解決好。10年前我們做paas時,和這個做法類似。不是說不好,時代變了,用腳本東拼西湊,終究難有好的系統。不能隻考慮現在的友善,容器技術和vm如果類比,我覺得會讓自己下決定時很糾結。

補充3:腳本一般是典型的運維工程師思維,quick &amp; dirty。一般很難做成一個産品或者系統。整體考慮和擴充性考慮都比較少。現在做docker的難點在于到底怎麼看待它。到底是拿它做排程的基本機關,還是部署的基本機關?考慮清楚,再聊方案。

<b>分享者簡介</b>

蕭田國,高效運維社群發起人,開放運維聯盟主席,複旦大學客座講師,網際網路專欄作者《高效運維最佳實踐》

張春源,目前任職csphere。國内最早期的docker實踐者,在生産環境擁有一年多的docker容器管理經曆。深刻了解docker對于開發、測試以及運維的價值。擅長利用docker建構整個devops自動化平台。熱愛專研dockerfile這門藝術,并對coreos有深入研究。

                                                        中生代技術群微信公衆号

高效運維之Docker持續部署圖文詳解前言