Jenkins Pipeline 流水線部署 Kubernetes 應(yīng)用
雖然云原生時(shí)代有了 JenkinsX、Drone、Tekton 這樣的后起之秀,但 Jenkins 這樣一個(gè)老牌的 CI/CD 工具仍是各大公司主流的使用方案。比如我司的私有云產(chǎn)品打包發(fā)布就是用這老家伙完成的。然而傳統(tǒng)的 Jenkins Slave 一主多從方式會(huì)存在一些痛點(diǎn),比如:
每個(gè) Slave 的配置環(huán)境不一樣,來完成不同語言的編譯打包等操作,但是這些差異化的配置導(dǎo)致管理起來非常不方便,維護(hù)起來也是比較費(fèi)勁
資源分配不均衡,有的 Slave 要運(yùn)行的 job 出現(xiàn)排隊(duì)等待,而有的 Slave 處于空閑狀態(tài)
資源有浪費(fèi),每臺(tái) Slave 可能是物理機(jī)或者虛擬機(jī),當(dāng) Slave 處于空閑狀態(tài)時(shí),也不會(huì)完全釋放掉資源。
正因?yàn)樯厦娴?Jenkins slave 存在這些種種痛點(diǎn),我們渴望一種更高效更可靠的方式來完成這個(gè) CI/CD 流程,而 Docker 虛擬化容器技術(shù)能很好的解決這個(gè)痛點(diǎn),又特別是在 Kubernetes 集群環(huán)境下面能夠更好來解決上面的問題,下圖是基于 Kubernetes 搭建 Jenkins slave 集群的簡(jiǎn)單示意圖:

從圖上可以看到 Jenkins Master 時(shí)以 docker-compose 的方式運(yùn)行在一個(gè)節(jié)點(diǎn)上。Jenkins Slave 以 Pod 形式運(yùn)行在 Kubernetes 集群的 Node 上,并且它不是一直處于運(yùn)行狀態(tài),它會(huì)按照需求動(dòng)態(tài)的創(chuàng)建并自動(dòng)刪除。這種方式的工作流程大致為:當(dāng) Jenkins Master 接受到 Build 請(qǐng)求時(shí),會(huì)根據(jù)配置的 Label 動(dòng)態(tài)創(chuàng)建一個(gè)運(yùn)行在 Pod 中的 Jenkins Slave 并注冊(cè)到 Master 上,當(dāng)運(yùn)行完 Job 后,這個(gè) Slave 會(huì)被注銷并且這個(gè) Pod 也會(huì)自動(dòng)刪除,恢復(fù)到最初狀態(tài)。
那么我們使用這種方式帶來了以下好處:
動(dòng)態(tài)伸縮,合理使用資源,每次運(yùn)行 Job 時(shí),會(huì)自動(dòng)創(chuàng)建一個(gè) Jenkins Slave,Job 完成后,Slave 自動(dòng)注銷并刪除容器,資源自動(dòng)釋放,而且 Kubernetes 會(huì)根據(jù)每個(gè)資源的使用情況,動(dòng)態(tài)分配 Slave 到空閑的節(jié)點(diǎn)上創(chuàng)建,降低出現(xiàn)因某節(jié)點(diǎn)資源利用率高,還排隊(duì)等待在該節(jié)點(diǎn)的情況。
擴(kuò)展性好,當(dāng) Kubernetes 集群的資源嚴(yán)重不足而導(dǎo)致 Job 排隊(duì)等待時(shí),可以很容易的添加一個(gè) Kubernetes Node 到集群中,從而實(shí)現(xiàn)擴(kuò)展。
上面的大半段復(fù)制粘貼自 基于 Jenkins 的 CI/CD (一) ??
kubernetes 集群
關(guān)于 kubernetes 集群部署,使用 kubeadm 部署是最為方便的了,可參考我很早之前寫過的文章《使用 kubeadm 快速部署體驗(yàn) K8s》,在這里只是簡(jiǎn)單介紹一下:
使用 kubeadm 來創(chuàng)建一個(gè)單 master 節(jié)點(diǎn)的 kubernets 集群
1 | root@jenkins:~ # kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.20.11 |
集群成功部署完成之后會(huì)有如下提示:
1 | Your Kubernetes control-plane has initialized successfully! |
查看節(jié)點(diǎn)狀態(tài)和 pod 都已經(jīng)正常
1 | root@jenkins:~ # kubectl get pod -A |
去除 master 節(jié)點(diǎn)上的污點(diǎn),允許其他的 pod 調(diào)度在 master 節(jié)點(diǎn)上,不然后面 Jenkins 所創(chuàng)建的 pod 將無法調(diào)度在該節(jié)點(diǎn)上。
1 | kubectl taint nodes $(hostname) node-role.kubernetes.io/master:NoSchedule- |
Jenkins master
至于 Jenkins master 的部署方式,個(gè)人建議使用 docker-compose 來部署。運(yùn)行在 kubernetes 集群集群中也沒什么毛病,可以參考 基于 Jenkins 的 CI/CD (一) 這篇博客。但從個(gè)人運(yùn)維踩的坑來講,還是將 Jenkins master 獨(dú)立于 kubernetes 集群部署比較方便??。
docker-compose.yaml
1 | version: '3.6' |
使用 docker-compose up 來啟動(dòng),成功啟動(dòng)后會(huì)有如下提示,日志輸出的密鑰就是
admin用戶的默認(rèn)密碼,使用它來第一次登錄 Jenkins。
1 | jenkins | 2021-03-06 02:22:31.741+0000 [id=41] INFO jenkins.install.SetupWizard#init: |
登錄上去之后,建議選擇
選擇插件來安裝,盡可能少地安裝插件,按需安裝即可。

在 Jenkins 的插件管理那里安裝上 kubernetes 插件

接下來開始配置 Jenkins 大叔如何與 kubernetes 船長(zhǎng)手牽手???????? :-)。配置 kubernets 的地方是在
系統(tǒng)管理 > 節(jié)點(diǎn)管理 > Configure Clouds。點(diǎn)擊Add a new cloud,來添加一個(gè) kubernetes 集群。

配置連接參數(shù)
| 參數(shù) | 值 | 說明 |
|---|---|---|
| 名稱 | kubernetes | 也是后面 pod 模板中的 cloud 的值 |
| 憑據(jù) | kubeconfig 憑據(jù) id | 使用 kubeconfig 文件來連接集群 |
| Kubernetes 地址 | 默認(rèn)即可 | |
| Use Jenkins Proxy | 默認(rèn)即可 | |
| Kubernetes 服務(wù)證書 key | 默認(rèn)即可 | |
| 禁用 HTTPS 證書檢查 | 默認(rèn)即可 | |
| Kubernetes 命名空間 | 默認(rèn)即可 | |
| WebSocket | 默認(rèn)即可 | |
| Direct Connection | 默認(rèn)即可 | |
| Jenkins 地址 | http://jenkins.k8s.li:8080 | Jenkins pod 連接 Jenkins master 的 URL |
| Jenkins 通道 | 50000 | Jenkins JNLP 的端口,默認(rèn)為 50000 |
| Connection Timeout | 默認(rèn)即可 | Jenkins 連接 kubernetes 超時(shí)時(shí)間 |
| Read Timeout | 默認(rèn)即可 | |
| 容器數(shù)量 | 默認(rèn)即可 | Jenkins pod 創(chuàng)建的最大數(shù)量 |
| Pod Labels | 默認(rèn)即可 | Jenkins pod 的 lables |
| 連接 Kubernetes API 的最大連接數(shù) | 默認(rèn)即可 | |
| Seconds to wait for pod to be running | 默認(rèn)即可 | 等待 pod 正常 running 的時(shí)間 |
在 Jenkins 的憑據(jù)那里添加上 kubeconfig 文件,憑據(jù)的類型選擇為
Secret file,然后將上面使用 kubeadm 部署生成的 kubeconfig 上傳到這里。

點(diǎn)擊連接測(cè)試,如果提示
Connected to Kubernetes v1.19.8就說明已經(jīng)成功連接上了 kubernetes 集群。

關(guān)于 pod 模板
其實(shí)就是配置 Jenkins Slave 運(yùn)行的 Pod 模板,個(gè)人不太建議使用插件中的模板去配置,推薦將 pod 的模板放在 Jenkinsfile 中,因?yàn)檫@些配置與我們的流水線緊密相關(guān),把 pod 的配置存儲(chǔ)在 Jenkins 的插件里實(shí)在是不太方便;不方便后續(xù)的遷移備份之類的工作;后續(xù)插件升級(jí)后這些配置也可能會(huì)丟失。因此建議將 pod 模板的配置直接定義在 Jenkinsfile 中,靈活性更高一些,不會(huì)受 Jenkins 插件升級(jí)的影響。總之用代碼去管理這些 pod 配置維護(hù)成本將會(huì)少很多。
Jenkinsfile
流水線
Jenkinsfile,下面是一個(gè)簡(jiǎn)單的任務(wù),用于構(gòu)建 webp-server-go 項(xiàng)目的 docker 鏡像。
1 | // Kubernetes pod template to run. |
pod 模版如下,將模板的內(nèi)容復(fù)制粘貼到上面的 Jenkinsfile 中。在容器中構(gòu)建鏡像,我們使用 dind 的方案:將 pod 所在宿主機(jī)的 docker sock 文件掛載到 pod 的容器內(nèi),pod 容器內(nèi)只要安裝好 docker-cli 工具就可以像宿主機(jī)那樣直接使用 docker 了。
1 | podTemplate( |
構(gòu)建
debian:buster-docker鏡像,使用它來在 pod 的容器內(nèi)構(gòu)建 docker 鏡像,使用的Dockerfile如下:
1 | FROM debian:buster |
定義好 jenkinsfile 文件并且構(gòu)建好 pod 模板中的鏡像后,接下來我們開始使用它來創(chuàng)建流水線任務(wù)。
流水線
在 Jenkins 上新建一個(gè)任務(wù),選擇任務(wù)的類型為
流水線

將定義好的 Jenkinsfile 內(nèi)容復(fù)制粘貼到流水線定義
Pipeline script中并點(diǎn)擊保存。在新建好的 Job 頁(yè)面點(diǎn)擊立即構(gòu)建來運(yùn)行流水線任務(wù)。

在 kubernetes 集群的機(jī)器上使用 kubectl 命令查看 pod 是否正常 Running
1 | root@jenkins:~ # kubectl get pod |
Job 正常運(yùn)行并且狀態(tài)為綠色表明該 job 已經(jīng)成功執(zhí)行了。

在 kubernetes 集群機(jī)器上查看 docker 鏡像是否構(gòu)建成功
1 | root@jenkins:~ # docker images | grep webps |
踩坑
pod 無法正常 Running
1 | Running in Durability level: MAX_SURVIVABILITY |
這是因?yàn)?Jenkins pod 中的 jnlp 容器無法連接 Jenkins master。可以檢查一下 Jenkins master 上 系統(tǒng)管理 > 節(jié)點(diǎn)管理 > Configure Clouds 中 Jenkins 地址 和 Jenkins 通道 這兩個(gè)參數(shù)是否配置正確。
結(jié)束
到此為止,我們就完成了讓 Jenkins 大叔與 kubernetes 船長(zhǎng)手牽手????????啦!上面使用了一個(gè)簡(jiǎn)單的例子來展示了如何將 Jenkins 的 Job 任務(wù)運(yùn)行在 kubernetes 集群上,但在實(shí)際工作中遇到的情形可能比這要復(fù)雜一些,流水線需要配置的參數(shù)也要多一些。
- END -
推薦閱讀 Kubernetes 企業(yè)容器云平臺(tái)運(yùn)維實(shí)戰(zhàn) 快、狠、準(zhǔn)!系統(tǒng)有效的排查運(yùn)維類故障 OpenStack 與 Kubernetes 的共存 Nginx 常用配置清單 最強(qiáng)整理!常用正則表達(dá)式速查手冊(cè) 運(yùn)維的工作邊界,這次真的搞明白了! 七年老運(yùn)維實(shí)戰(zhàn)中的 Shell 開發(fā)經(jīng)驗(yàn)總結(jié) 面試數(shù)十家Linux運(yùn)維工程師,總結(jié)了這些面試題(含答案) 快速入門 Ansible 自動(dòng)化運(yùn)維工具 | 16張圖 12年資深運(yùn)維老司機(jī)的成長(zhǎng)感悟
點(diǎn)亮,服務(wù)器三年不宕機(jī)


