基於K8s和docker的Jenkins 可伸縮持續集成系統

概述

本文檔主要介紹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

2.        http://172.25.8.10:9080

	  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鏡像需要進行定製,網上下載的鏡像僅保證最簡單的連接。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章