概述
本文檔主要介紹Jenkins的可伸縮部署方式,一種是基於Docker(或者docker-swarm 集羣)的部署方式,另外一種是基於kubernetes的部署方式。
由於基於kubernetes也是基於docker的,都需要用到docker進行通信和中轉,因此使用同一的slave鏡像將大大節省平臺開發與維護成本,因此需要引入jenkins的另一個大插件pipeline。Pipeline也是jenkins 2.0以後的主要方向和升級。
Jenkins系統基於docker的應用
jenkins介紹及傳統部署遇到的問題
Jenkins 是開源的一套持續集成框架,可以進行大規模的編譯、測試和發佈的工作,給軟件開發團隊帶來極大的便利性。
Jenkins 的持續集成環境可以是集羣化的,主要的運行模式爲master-slave模式。
Jenkins 的master爲Jenkins系統的控制節點,slave節點負責具體的項目編譯測試等工作。
由於大公司裏面需要進行編譯的工程或者對象非常龐大,因此需要大量的物理節點作爲slave,而且這些環節相對固定,可能很難適應其他項目的編譯測試,一旦salve節點遭到破壞,需要人爲的進行修復甚至重建,非常麻煩。Docker 來解決問題
Docker的問世,爲我們提供瞭解決方案,使用docker作爲jenkins slave節點可以解決slave節點遭到破壞後遇到的問題, 而且大量的工程不是每時每刻同時運行的因此可以在需要時吧docker拉起來進行編譯測試,這樣就節約了大量的物理節點, 解決了上述問題。
然而使用docker 同樣需要集羣,因此要用到集羣管理工具, swarm 或者kubernetes。Swarm 一般用在小集羣上,而且swarm和docker本身的藉口完全一致, 因此這裏就簡單介紹單點docker節點作爲slave。 Kubernetes作爲大的docker 集羣管理工具,當jenkins的工程數量非常大的時候可以用kubernetes, kubernetes的運維相對比docker 和swarm的門檻要高一點。
Jenkins master也可以使用docker來運行或者使用kubernetes來提供高可用的jenkins master。本文不對jenkins master的安裝和docker運行做過多的說明。
kubernetes 管理Jenkins slave
Kubernetes 主要是用來進行docker 調度運行的,同樣因爲這一點通過kubernetes插件的配置,不需要管slave節點是否在線,因爲kubernetes幫你負責創建和連接。這樣就可以做到沒有任務的時候沒有任務slave節點在線,做到完全的按需啓動slave和調度slave。
使用kubernetes 部署管理的jenkins slave如下:
Jenkins master 的部署
簡單說明 jenkins master的安裝與運行
1) 物理機上的安裝
以centos爲例:
yuminstall –y java java-devel
由於centos自己的yum源並沒有包含jenkins因此需要添加jenkins對應的源
wget -O /etc/yum.repos.d/jenkins.repohttp://pkg.jenkins-ci.org/redhat-stable/jenkins.repo
rpm--import http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key
yum install –y Jenkins
修改jenkins 的配置文件 /etc/sysconfig/jenkins
systemctl enable jenkins.service
systemctl start jenkins.service
2) 使用docker來運行
自己製作鏡像或者網上下載jenkins_master的鏡像。(我這裏是下載的鏡像)
dockerrun –idt –v /home/jenkins:/home/jenkins -v /home/data:/var/jenkins_home -p8080:8080 -p 50000:50000 jenkins-master
這樣既可。
https://hub.docker.com/_/jenkins/ 可以下載到jenkins master鏡像
Jenkinsmaster配置和插件安裝
jenkins 系統初始化
這裏以jenkins master運行在docker 中爲例
1) 這裏每次全新的jenkins初始化的時候都會有一個任意的密碼,路徑在/var/jenkins_home/secrets/initialAdminPassword,按 照提示解鎖jenkins:
2) 解鎖後,系統會根據網絡情況提示安裝一些插件:
3) 安裝過程如下:
安裝完成後設置系統管理員賬戶和密碼。
然後登陸即可使用。
Jenkins Docker 插件安裝與kubernetes 插件安裝
1) 插件更新中心配置:
登陸jenkins-->系統管理-->插件管理-->高級
首先配置涉及站點,默認的是 官方的:http://updates.jenkins-ci.org/update-center.json
也可以配置日本的或者俄羅斯的 http://mirror.esuni.jp/jenkins/updates/update-center.json
http://mirror.yandex.ru/mirrors/jenkins/updates/update-center.json
配置完以後必須點右下角的立即獲取
也可以在可選插件哪個頁面的下面點擊獲取。
2) 安裝需要的插件:
在可選插件頁面勾選需要安裝的插件,點擊直接安裝即可。
例如選擇smartjenkins插件:
我們這裏需要找的是kubernetes的插件和docker的插件進行安裝,如果安裝過程中有些插件安裝失敗,則手動下載插 件然後再高級裏面選擇上傳插件進行安裝:
直到安裝完成所有需要的插件。
注:pipeline的插件在一開始初始化的時候安裝完成了。
使用docker運行jenkins slave並連接到master
Jenkins master 連接slave 有兩種模式,一直是master主動發起連接,主要通過ssh 來進行連接,另外一種是slave 主動連接master,使用的jnlp協議。
我們使用docker來運行jenkins slave 都可以,但是要做到沒有任務在編譯測試的時候沒有slave在線則只能通過 jnlp來進行連接而去必須使用kubernetes來調度。
我們這裏討論的是使用單獨的或者幾個slave長期在線,進行項目的編譯測試,都是由master發起連接的。
https://hub.docker.com/u/jenkinsci/ slave鏡像下載地址上
docker 運行jenkins slave (ssh 模式)
這種模式docker 運行一個slave 容器跟普通物理機使用完全一致,這裏不做說明。
同樣可以再在同一個slave節點(docker 容器)上綁定很多個工程或者任務。
docker 運行jenkins slave (jnlp 模式)
Jnlp 模式的則相對應用的比較少,jnlp 是由jenkins slave節點(物理節點,虛機或者容器均可)發起連接的, 他 會根據配置的jenkins master的url , Jenkins連接的token和jenkins slave name( lable)來進行進行連接。
舉個例子:
登錄jenkins-->系統管理-->節點管理-->新建節點
那麼slave 進行運行連接的時候4個參數是:
1. –url
3. 54cf091374806d8db7b9cd3977e23d080c955fa6fa33dd6c33dd594aa7b79350
4. jnlp_test
command as : Jenkins-slave –url http://172.25.8.10:8090 54cf091374806d8db7b9cd3977e23d080c955fa6fa33dd6c33dd594aa7b79350 jnlp_test
之後的編譯跟ssh 模式一模一樣
如何做到方便高效已經保持少量的slave在線
上面介紹的這兩種方式都是使用一個slave進行任務的編譯測試,跟傳統的部署方式對比僅僅只是增加了編譯環境的數 量,但是每個編譯環境跟物理機基本一致。
而且由於docker 環境需要進行調試和連接master,也比較麻煩,作爲代碼開發者一般只管理工程代碼怎樣編譯,可能 根本不懂jenkins,怎麼辦?
大量的jenkins-slave(dokcer)在線jenkinsmaster的管理效率低下,而且可能由於slave(docker)在線,某些任務的編 譯資源被擠佔,編譯效率下降,怎麼辦?
這些問題的解決辦法是使用docker in docker 來處理。
每個物理節點上長時間的只有一個jenkins-slave(進程或者docker容器都行,最好是容器—無狀態,可重新來,降低運 維成本),所有的任務綁定到這幾個slave上,每個任務的編譯過程是啓動自己的容器——下載代碼——編譯——測試等。
把編譯過程寫成腳本:
docker pull
docker run
docker exec *** git clone
docker exec build
***
那麼什麼是docker in docker
使用docker in docker 來進行CI
Dockerin docker 就是在docker中運行docker, 單實質上是將host的docker.sock 掛載到容器中,然後再容器中創建的容器,其實是運行在host機器上呢。
使用docker in docker 來進行CI
Docker in docker其實就是讓一個物理機上只有一個jenkins slave在運行,這個jenkinsslave 僅僅只負責任務轉發,相當於是一個標準接口, 這樣開發人員只需要知道自己的軟件需要什麼樣的docker環境進行編譯,而不用關注這個docker 容器怎樣跟jenkins master連接。
這時候 Jenkins slave的運行如下:
docker run -it -u root -v /var/run/docker.sock:/var/run/docker.sock my_jnlp_test:0.1 -url http://172.25.8.10:9080 54cf091374806d8db7b9cd3977e23d080c955fa6fa33dd6c33dd594aa7b79350 jnlp_test
同樣帶來一些問題,例如 docker 腳本的編寫,docker狀況的監控,編譯構建結果的查看與測試等等。
Docker 插件和pipeline 插件幫你搞定這些。
pipeline 來解決docker in docker帶來的問題
Pipeline是jenkins 2.0 的主要升級。其主要是用來定義工作流的,這裏結合docker來更好管理docker in docker 的編譯。
同樣對於多個依賴關係的任務進行更好的CI 管理,同時其stage view 更直觀的反應CI運行的狀況。
Pipeline工程的創建和配置:
Jenkins-->新建-->需要選擇pipeline
項目配置中僅僅需要配置pipeline部分
寫一段pipeline script 就可以進行構建了
node('jnlp_test1'){
stage "Container Prep"
docker.image('my_docker:0.1').inside{
stage 'Checkout'
git url:'http://101.71.10.3:15480/chenmiao/dhcAPI.git'
stage 'Build'
sh "mvn clean package"
}
}Node 用來制定在哪一個slave節點上進行構建
Stage 用來給任務分段
這些具體的得看自己學習啦,我這裏也是簡單的一個例子。
編譯的效果如下:
比較清晰的顯示出每一個階段用了多長時間,哪個階段失敗了。
這個到目前爲止解決了基於固定的物理服務器,儘可能少的在線編譯問題,但不能解決佔用衝突—即可能1000個任務中只有20個在線,但這20個在線的任務是同一個物理服務器上的,結果是編譯依舊非常低效。kubernetes進行按需創建slave
kubernetes 的引入是爲了高效平衡的對docker進行調度,可以有效解決上述的問題。
Jenkins環境上kubernetes的配置:
登錄Jenkins-->系統管理-->系統設置:
搜索“雲” -->增加一個雲-->kubernetes
然後配置kubernetes:
這裏必配項有:Name、Kubernetes URL、kubernetesNamespace、 Jenkins URL 以及 Kubernetes Pod Template(大項,這一項最少需要一個,否則不能使用kubernetes)
再來配置jenkins-slave 對應的docker的信息,由於kubernetes是報docker封裝成Pod來管理,即配置kubernetes Pod Template:
這裏需要名卻的是第一處的Name 就是子啊項目配置時的slave節點,label 是kubernetes進行管理用的。其餘的配置項爲slave容器需要的配置。
Jenkins ci工程的配置
Pipeline Test1 for example:
這裏只需要指定node爲kubernetes Pod配置的哪個名字即可。
自由風格的工程配置一樣:
這樣既可以在對應的docker 裏面進行項目CI。
在沒有任務運行的時候,系統上是沒有slave的:
Kubernetes get pod的結果也一樣沒有jnlp-slave的Pod
root@debian:/home/Daniel/jnlp_slave# kubectl -s 172.25.5.150:8080 get pod --all-namespaces -o wide NAMESPACE NAME READY STATUS RESTARTS AGE NODE default kube-apiserver-172.25.5.150 1/1 Running 3 14d 172.25.5.150 default kube-controller-manager-172.25.5.150 1/1 Running 0 14d 172.25.5.150 default kube-scheduler-172.25.5.150 1/1 Running 0 14d 172.25.5.150 kube-system kube-ui-v1-1dn43 1/1 Running 0 10d 172.25.5.155 |
運行任務時:
Kubernetes got pod 中有jnlp-slave 的pod
root@debian:/home/Daniel/jnlp_slave# kubectl -s 172.25.5.150:8080 get pod --all-namespaces -o wide NAMESPACE NAME READY STATUS RESTARTS AGE NODE default kube-apiserver-172.25.5.150 1/1 Running 3 14d 172.25.5.150 default kube-controller-manager-172.25.5.150 1/1 Running 0 14d 172.25.5.150 default kube-scheduler-172.25.5.150 1/1 Running 0 14d 172.25.5.150 jenkins jnlp-slave-4eeed2fbc128e 0/1 Running 0 3s 172.25.5.155 kube-system kube-ui-v1-1dn43 1/1 Running 0 10d 172.25.5.155 |
問題記錄
1. 我們使用的kubernetes版本不支持Pod name 和lable中使用下劃線,因此前期Pod一直創建不成功。
2. Kubernetes Pod template 中Container的配置項 Commandto run slave agent 以及Arguments topass to the command配置一直有錯誤:Command 最好使用全路徑, Arguments 最好用括號
3. Jenkins master 和jenkins slave 運行的時候需要掛載卷,這些卷如果是host上的目錄需要將其的所有者改爲jenkins 裏面運行的用戶,而且容器裏面的卷也需要修改其所有者。
chown Jenkins:Jenkins/home/Jenkins 爲例
4. Jenkins maste 和jenkins slav鏡像需要進行定製,網上下載的鏡像僅保證最簡單的連接。