1. 程式人生 > 其它 >docker持續整合java專案

docker持續整合java專案

前言

關於Docker的文章鋪天蓋地,但精品文章往往翻譯居多。都說Docker天生適合持續整合/持續部署,但同樣,可落地、實際可操作性的文章也很罕見。

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

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

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

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

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

好吧,我們正式開始。

1. 持續部署的技術思路

在本例中,假設我們JAVA專案的名稱為hello。簡要的技術思路如下。

本案例中假設程式碼託管在git.oschina.com上,JenkinsDocker Registry(類似於yum源)各執行在一個Docker容器中。JAVA專案自己也單獨執行在一個叫hello的容器中。

本文采取的持續部署方案,是從私有的Docker Registry拉取程式碼。有些變通的方案,把程式碼放在宿主機上,讓容器通過卷組對映來讀取。這種方法不建議的原因是,將程式碼拆分出容器,這違背了Docker的集裝箱原則:

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

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

容器即程序。我們採用上述方案做Docker持續部署的原因和意義,也在於此。容器的生命週期,應該遠遠短於虛擬機器,容器出現問題,應該是立即殺掉,而不是試圖恢復。

2. 效果展示

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

2.1 程式程式碼更新前的效果

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

2.2 提交程式程式碼更新

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

2.3 上傳新程式碼到Git

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

然後呢?

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

為什麼需要3~5分鐘?只是因為本案例中的JAVA專案,需要從國外download Maven程式包,以供Jenkins呼叫和編譯JAVA。正式應用環境中,可以把Maven源放在國內或機房。如果僅僅需要對PHP專案做持續部署,那就更快捷了。

2.4 檢視程式碼更新後的效果

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

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

3. 配置GitJenkins聯動

這個過程也是難者不會,會者不難。主要分為如下三步。

3.1 Jenkins配置Git

Jenkins中新建專案java-app,並配置從Git拉取程式程式碼。具體如下:

3.2 Jenkins配置遠端構建

Jenkins中配置token,以供git遠端呼叫時使用。

3.3 Git開啟鉤子

怎麼讓Git在接收到使用者更新的程式碼後,把訊息和任務傳遞給Jenkins呢?這藉助於Githook功能,配置起來也非常簡單,如下。

4. 配置Jenkins自動更新程式碼

Jenkins的主要工作是配置"遠端構建"。在接收到Git傳遞過來的訊息後,觸發這個遠端構建(到目標伺服器),按照預定義的任務列表,執行一系列的工作,重建容器等。詳見如下:

我們把其中最關鍵的Shell指令碼內容摘抄出來。這些Docker相關操作,在第1部分"技術思路"已經提及,不再贅述。

5. 效果圖文詳解

2.3這個章節中,我們當時的操作如下,這個目的是向Git提交更新程式碼。

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

5.1 上傳程式碼到Git

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

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

5.2 Jenkins進行的精彩互動

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

1Jenkins會自動"冒出來"一個構建任務。

2)我們點進來,看看具體操作日誌。是的,正在接受來自Git的任務。

3)下載Maven相關的軟體包(就是這個過程慢)。

4)下載完成後,就開始利用maven BUILD 新的hello專案包。

5)然後重建Maven容器,構建新的ImagePushDocker私有庫中。

6)最後,重新把Docker容器拉起來。這樣,又新生了。呵呵

6. FAQ

**問題1**採用這麼相對複雜的辦法(而不是把更新程式碼放在宿主機然後卷組對映),是因為專案基於JAVA麼;是否PHP專案就可以採用更新程式碼放在宿主機然後卷組對映這種方式?

**回答1**將程式碼拆分出容器,違背了集裝箱原則。導致裝卸複雜度增加。從貨運工人角度考慮,整體才是最經濟的。一切版本化。拋棄過去的檔案分發。這是正途。至於檔案大小,大的war包也就50M100M,在現有網路下不成問題,效能問題最好優化。另外建議關注docker 2 dockerp2p傳輸。

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

**回答2**如果你的程式碼500M,那隻能說明業務開發該打板子了。

**問題3**如果測試環境使用您提供的完整集裝箱服務還行,但在生產環境,叢集裡執行docker做應用,如果每個容器都是有完整的程式碼,是否有點臃腫,不如每個叢集節點裡就執行基礎服務映象,通過卷組功能繫結共享儲存裡的程式碼,加上CrontabPythonShell指令碼,這樣每次程式碼更新就1次就行了。

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

**補充3**指令碼一般是典型的運維工程師思維,quick & dirty。一般很難做成一個產品或者系統。整體考慮和擴充套件性考慮都比較少。現在做docker的難點在於到底怎麼看待它。到底是拿它做排程的基本單位,還是部署的基本單位考慮清楚?再聊方案。

**張春源,**目前任職cSphere。國內最早期的Docker實踐者,在生產環境擁有一年多的Docker容器管理經歷。深刻理解Docker對於開發、測試以及運維的價值。擅長利用Docker構建整個DevOps自動化平臺。熱愛專研Dockerfile這門藝術,並對CoreOS有深入研究。