搭建 Jenkins+Docker 自動化整合環境
一、關於Jenkins
Jenkins簡介
Jenkins可以幫你構建一個自動化的持續整合環境,你可以使用它來“自動化”編譯、打包、分發部署你的應用,它相容 ant、maven、gradle 等多種第三方構建工具,同時跟 svn、git 能無縫整合,也支援直接與知名原始碼託管網站,比如 github、bitbucket 直接整合。
Jenkins安裝
Jenkins的安裝十分簡單,你可以從官網 http://mirrors.jenkins-ci.org/war/latest/ 直接下載 war 包,使用 java -jar jenkins.war,或者放到 Tomcat 類似的容器裡執行都可以(JDK 版本建議使用 1.6 以上來執行)。Jenkins 預設啟動埠是8080,請注意端口占用。另外,Jenkins 檔案其實都在~/.jenkins 目錄下,執行過程中你可以在這裡找到你執行過的 job 和相應的日誌檔案。
首次安裝,可以把外掛都安裝上,自己都試試看。如果因為網路原因,外掛下載失敗的,可以從失敗詳情中把地址拷出來,下載後,以上傳 hpi 檔案的方式安裝。
系統設定
安裝完成的第一步,先到 Blobal Tool Configuration 中配置相關的環境,如JDK、MAVEN、GIT 等,相應的路徑設定都是設定 Jenkins 這臺機子本地的目錄。建議把所有的配置都完善下,否則日後的執行中可能會出現一些小問題,可以試下點選?檢視幫助,還是很有用的。
Jenkins叢集配置
叢集配置也十分簡單,就是新增 slave 節點的過程。點選系統管理->管理節點->新建節點,各個配置後面都有詳細的幫助說明的。在啟動方法這裡推薦使用 Launch slave agents on UNIX machines via SSH,這樣master節點會主動使用 SSH 登陸到 slave 節點上,並執行 java -jar slave.jar,這樣一個slave節點就新增完成了。
構建Job
其實到這一步,就是 jenkins 的常規流程了,你可以參照建立 Job 選項的介面的各個配置,制定你構建計劃,或者我們直接使用指令碼來完成我們的構建操作(建議)選擇構建 Execute shell,文章末尾會附上一個完整專案的 shell 構建流程。
Pipeline
Pipeline 字面意思就是流水線,很好用的 Jenkins 的一個外掛,將很多步驟按順序排列好,做完一個執行下一個。真實的工作環境有很多 job,比如先編譯,然後執行靜態程式碼檢查、單元測試、然後部署伺服器、伺服器重啟、進行 ui 測試等。我們需要對這些 job 進行一些設定將它們的上下游關係配置好。
這時候 Pipeline 就派上用場了。在 Jenkins 主頁點選新建檢視,然後選擇 Build Pipeline View,然後填寫 Select Initial Job,構建後的操作可以選擇其他的 Job,以此類推,這樣一個流水線就完成了。Pipeline 提供檢視介面,你可以在檢視上形象地看到整個構建計劃的執行流程和完成度。
二、關於Docker
Docker 簡介
Docker 現在是 Github 社群最火的專案之一,Docker 是個容器,或許你聽過 lxc,你可能知道 Tomcat 這個 Web 容器,容器是什麼概念,意會就好。問個問題,你想在一臺機子上執行一個 java6 的應用,又想執行一個 java8 應用怎麼辦;或者說你開發出一個軟體,mac 版、windows 版本,我都想執行,怎麼辦?裝虛擬機器?不不不,虛擬機器太浪費資源了,Docker 這時候就派上用場了,在電腦上,你可以同時裝一個mac 的容器和 windows 的容器哦。一個虛擬機器可能會消耗2到3G的記憶體,一個容器僅僅只消耗幾百M的資源哦。
Docker 安裝
具體安裝細節,可以參照 https://docs.docker.com,文件說得很清楚了。 Docker 原本是開發在 Linux 上的,Windows 下是採用 Docker machine 的方式,起一個虛擬機器在虛擬機器裡面跑 Docker。本來呢Mac也是採用虛擬機器的方式,後來有了 Docker for mac,採用 HyperKit,一種更輕量級的虛擬化方式。當然,你還是可以用 Docker machine 的方式執行。
Docker 基礎
搞清楚兩個概念,容器與映象。打個比方吧。裝機,容器就是裝完成後的系統,映象就是 ISO 安裝盤,系統映象。
作為一個合格的程式設計師,你一定用過 Git 的吧,pull,commit,push……寫程式碼過程就是這樣,先拉取程式碼pull,然後是在一個基礎的文字上不斷地增加 commit,加積木一樣,一層層疊加,累積上去,最後再 push 上去。沒錯 Docker 就是採用這種形式。
簡單介紹下 Docker 命令:
Docker version / Docker info 檢視基本資訊,遇到使用問題或者BUG,可以到社群裡報告,記得帶著這些資訊哈。
Docker pull 拉取映象。
Docker run 從映象建立一個容器並執行指定的命令常用引數-i -d,建議用—-name命名這個容器,命名後可以使用容器名訪問這個容器。
Docker attach(不推薦使用)。
Docker exec -ti CONTAINER /bin/bash 連線到容器上執行bash
Docker logs CONTAINER 檢視日誌,如run命令後的執行結果,Docker logs -f 檢視實時的日誌。
Docker kill 殺死Docker容器程序,你可以使用Docker kill $(Docker ps -aq)殺死所有的Docker程序,後者打印出所有的容器的容器id(包括正在執行的,和沒有執行的)。
Docker rm CONTAINER 刪除一個容器,記得要先停止正在執行的容器,再去刪除它。
Docker exec -it <container_id> bash -c ‘cat > /path/to/container/file’ < /path/to/host/file/容器外向容器內複製檔案(也可以用掛載的形式哦)。
Docker commit -a “mike” -m “映象的一些改動” CONTAINER 當你在容器內做了某種操作後,如增加了一個檔案,你可以用這個命令把修改提交,重新打包為映象。
Docker push 推送映象。。到這裡是不是覺得跟Git的模式已經有點像了呢。
Docker history IMAGES 檢視映象的修改歷史。
Docker ps -a | grep “Exited” | awk ‘{print $1 }’| xargs Docker rm 刪除exited的容器。
Docker rmi $(Docker images | awk ‘/^<none>/ {print $3}’) 刪除tag為NONE的容器。
Dockerfile基礎
Dokcerfile,是的,你還是要稍微掌握下 Dockerfile 的寫法。
- From 每個 Dockerfile 映象的構建都會基於一個基礎映象,這是你一來的基礎映象 name:tag,git。
- MAINTAINER (不用記,作者簽名)。
- ENV 配置環境變數。
- COPY 複製本地。
- EXPOSE 暴露容器的埠。
- WORKDIR 後續命令的執行路徑。
- RUN important!,執行相應的命令,這一步是在容器構建這一步中執行的命令,一般用作安裝軟體,操作的結果是持久化在容器裡面儲存下來的。
- Tips:每次執行RUN的時候都是再預設路徑執行的,如果要到固定路徑下執行命令請在之前加WORKDIR,或者使用RUN (cd workpath && echo “mike”)這樣把cd命令跟相應的執行命令用闊號括起來。
- ENTRYPOINT 容器啟動後執行的命令。
三、Jenkins+Docker自動化整合環境搭建
這一步,我們把 Jenkins 和 Docker 結合起來。Jenkins 本身版本比較老,雖然外掛多,但許多外掛沒有人在維護更新,環境本身還是比較舊的,且各式各樣的工程如果都用外掛來安裝,這樣的外掛不一定滿足要求,所以建議配合 Docker 來搭建測試環境。
如果說好處的話,還有比較激進的一段話(建議略過哈):
我們把一個工程程式碼開發後的測試流程簡單分為編譯、部署(事實上可能更多,如專案程式碼有多個工程,工程間有相互依賴)。如果我們想在一個 slave 節點上既執行 Java7 應用,又執行 Java8 應用,哦,Jenkins 有相應的外掛解決?那如果是 NodeJs4 應用和 NodeJs5 應用呢?JAVA 升級到9了,外掛沒更新?像一些複雜的工程,如 JDK 自身的編譯、如 Docker 專案的編譯,我需要安裝各種依賴,就可能會汙染全域性空間,這時候就建議把編譯過程放到容器裡,或者說我要在 Linux 上編譯部署一個 Windows 應用,在一個 Windows 容器裡部署就可以了。
再比如,如果我們用 omad 部署 web 應用可能要考慮埠衝突,部在 Docker 容器裡,工程程式碼的埠,都不用變。還有,容器作測試環境的話,如果要保證線上,線下環境一致,甚至可以複製一個線下容器,直接在線上跑容器的。還有……
大致的想法是,我們用 Jenkins 來做節點控制、版本管理、流程設定、觸發 Job,用 Docker 來搭建編譯部署環境。把這一切連線起來的就是流程指令碼和 Dockerfile 的編寫。
實現細節可以參照下面的示例。
觸發條件:由 Jenkins 控制,如設定定時執行,或者 github 中的每一個 commit,或者每一個 PR 執行一次。
構建流程:各個環節,Job,之間用 Pipeline 來實現整個構建流程的控制。
構建Job:這裡,我覺得可以分為兩種情況,一種是把拉取程式碼的過程和構建編譯環境的過程都放到 Dockfile 裡面,這適用於比較複雜的編譯環境,如 Docker 本身的編譯需要安裝許多的依賴,對依賴的版本都有不同的要求,還是建議把編譯環境放在容器的裡面。另一種情況,為求省事方便,如 java 工程,編譯一般用 maven 等構建工具來完成的話,大可以放在外面,只是把執行環境搬到 Docker 容器裡。
Execute shell:
Dockerfile:
配置基礎執行環境。
如果需要編譯,配置編譯環境,可以在容器內拉取程式碼,執行編譯。
web應用暴露埠。
配置應用啟動命令。
另外,容器裡你都可以配置成8080埠,暴露8080埠,只要再 Docker run -p *:8080,執行時改下相應的埠對映就可以了。