使用 Jenkins Pipeline 來自動化部署一個 Kubernetes 應用的方法,在實際的項目中,往往一個代碼倉庫都會有很多分支的,比如開發、測試、線上這些分支都是分開的,一般情況下開發或者測試的分支希望提交代碼後就直接進行 CI/CD 操作,而線上的話最好增加一個人工干預的步驟,這就需要 Jenkins 對代碼倉庫有多分支的支持,當然這個特性是被 Jenkins 支持的。
Jenkinsfile
學習連接:https://www.jenkins.io/doc/book/pipeline/syntax/
新建一個 Jenkinsfile 文件,將上節課的構建腳本拷貝進來,但是需要對其做一些修改:(Jenkinsfile)
node('haimaxy-jnlp') {
stage('Prepare') {
echo "1.Prepare Stage"
checkout scm
script {
build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
if (env.BRANCH_NAME != 'master') {
build_tag = "${env.BRANCH_NAME}-${build_tag}"
}
}
}
stage('Test') {
echo "2.Test Stage"
}
stage('Build') {
echo "3.Build Docker Image Stage"
sh "docker build -t cnych/jenkins-demo:${build_tag} ."
}
stage('Push') {
echo "4.Push Docker Image Stage"
withCredentials([usernamePassword(credentialsId: 'dockerHub', passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
sh "docker login -u ${dockerHubUser} -p ${dockerHubPassword}"
sh "docker push cnych/jenkins-demo:${build_tag}"
}
}
stage('Deploy') {
echo "5. Deploy Stage"
if (env.BRANCH_NAME == 'master') {
input "確認要部署線上環境嗎?"
}
sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s.yaml"
sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s.yaml"
sh "kubectl apply -f k8s.yaml --record"
}
}
在第一步中增加了checkout scm命令,用來檢出代碼倉庫中當前分支的代碼,爲了避免各個環境的鏡像 tag 產生衝突,爲非 master 分支的代碼構建的鏡像增加了一個分支的前綴,在第五步中如果是 master 分支的話才增加一個確認部署的流程,其他分支都自動部署,並且還需要替換 k8s.yaml 文件中的環境變量的值。
更改完成後,提交 dev 分支到 github 倉庫中。
BlueOcean
官方文檔:https://www.jenkins.io/projects/blueocean/
使用 BlueOcean 這種方式來完成此處 CI/CD 的工作,BlueOcean 是 Jenkins 團隊從用戶體驗角度出發,專爲 Jenkins Pipeline 重新設計的一套 UI 界面,仍然兼容以前的 fressstyle 類型的 job,BlueOcean 具有以下的一些特性:
- 連續交付(CD)Pipeline 的複雜可視化,允許快速直觀的瞭解 Pipeline 的狀態
- 可以通過 Pipeline 編輯器直觀的創建 Pipeline
- 需要干預或者出現問題時快速定位,BlueOcean 顯示了 Pipeline 需要注意的地方,便於異常處理和提高生產力
- 用於分支和拉取請求的本地集成可以在 GitHub 或者 Bitbucket 中與其他人進行代碼協作時最大限度提高開發人員的生產力。
BlueOcean 可以安裝在現有的 Jenkins 環境中,也可以使用 Docker 鏡像的方式直接運行,這裏直接在現有的 Jenkins 環境中安裝 BlueOcean 插件:登錄 Jenkins Web UI -> 點擊左側的 Manage Jenkins -> Manage Plugins -> Available -> 搜索查找 BlueOcean -> 點擊下載安裝並重啓
安裝完成後,可以在 Jenkins Web UI 首頁左側看到會多一個 Open Blue Ocean 的入口,點擊就可以打開,如果之前沒有創建過 Pipeline,則打開 Blue Ocean 後會看到一個Create a new pipeline的對話框:
然後點擊開始創建一個新的 Pipeline,可以看到可以選擇 Git、Bitbucket、GitHub,這裏選擇 GitHub,可以看到這裏需要一個訪問 GitHub 倉庫權限的 token,在 GitHub 的倉庫中創建一個 Personal access token
然後將生成的 token 填入下面的創建 Pipeline 的流程中,然後就有權限選擇自己的倉庫,包括下面需要構建的倉庫,比如這裏需要構建的是 jenkins-demo 這個倉庫,然後創建 Pipeline 即可:
Blue Ocean 會自動掃描倉庫中的每個分支,會爲根文件夾中包含Jenkinsfile的每個分支創建一個 Pipeline,比如這裏有 master 和 dev 兩個分支,並且兩個分支下面都有 Jenkinsfile 文件,所以創建完成後會生成兩個 Pipeline:
可以看到有兩個任務在運行了,可以把 master 分支的任務停止掉,只運行 dev 分支即可,然後點擊 dev 這個 pipeline 就可以進入本次構建的詳細頁面:
在上面的圖中每個階段都可以點擊進去查看對應的構建結果,比如可以查看 Push 階段下面的日誌信息:
[jenkins-demo_dev-I2WMFUIFQCIFGRPNHN3HU7IZIMHEQMHWPUN2TP6DCYSWHFFFFHOA] Running shell script
+ docker push ****/jenkins-demo:dev-ee90aa5
The push refers to a repository [docker.io/****/jenkins-demo]
...
Docker 鏡像的 Tag 爲dev-ee90aa5,是符合在 Jenkinsfile 中的定義
更改下 k8s.yaml 將 環境變量的值的標記改成 BRANCH_NAME,當然 Jenkinsfile 也要對應的更改,然後提交代碼到 dev 分支並且 push 到 Github 倉庫,可以看到 Jenkins Blue Ocean 裏面自動觸發了一次構建工作,最好同樣可以看到本次構建能夠正常完成,最後查看下本次構建的結果:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
jenkins-demo-648876568d-q5mbx 0/1 Completed 3 57s
...
$ kubectl logs jenkins-demo-648876568d-q5mbx
Hello, Kubernetes!I'm from Jenkins CI!
BRANCH: dev
可以看到打印了一句 BRANCH: dev ,證明我本次 CI/CD 是正常的。
現在來把 dev 分支的代碼合併到 master 分支,然後來觸發一次自動構建:
☁ jenkins-demo [dev] git status
On branch dev
nothing to commit, working directory clean
☁ jenkins-demo [dev] git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
☁ jenkins-demo [master] git merge dev
Updating 50e0401..ee90aa5
Fast-forward
Jenkinsfile | 29 +++++++++--------------------
k8s.yaml | 3 +++
main.go | 2 ++
3 files changed, 14 insertions(+), 20 deletions(-)
☁ jenkins-demo [master] git push origin master
Total 0 (delta 0), reused 0 (delta 0)
To [email protected]:cnych/jenkins-demo.git
50e0401..ee90aa5 master -> master
回到 Jenkins 的 Blue Ocean 頁面中,可以看到一個 master 分支下面的任務被自動觸發了,同樣進入詳情頁可以查看 Push 階段下面的日誌:
...
[jenkins-demo_master-XA3VZ5LP4XTCFAHHXIN3G5ZB4XA4J5H6I4DNKOH6JAXZXARF7LYQ] Running shell script
+ docker push ****/jenkins-demo:ee90aa5
...
可以查看到此處推送的鏡像 TAG 爲 ee90aa5,沒有分支的前綴,是不是和前面在 Jenkinsfile 中的定義是一致的,鏡像推送完成後,進入 Deploy 階段的時候可以看到出現了一個暫停的操作,讓選擇是否需要部署到線上,前面是不是定義的如果是 master 分支的話,在部署的階段需要人工確認:
點擊Proceed纔會繼續後面的部署工作,確認後,同樣可以去 Kubernetes 環境中查看下部署的結果:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
...
jenkins-demo-c69dc6fdf-6ssjf 0/1 Completed 5 4m
...
$ kubectl logs jenkins-demo-c69dc6fdf-6ssjf
Hello, Kubernetes!I'm from Jenkins CI!
BRANCH: maste
現在可以看到打印出來的信息是 master,證明部署是沒有問題的。
到這裏就實現了多分支代碼倉庫的完整的 CI/CD 流程。
當然這裏的示例還是太簡單,只是單純爲了說明 CI/CD 的步驟,在後面的課程中,會結合其他的工具進一步對現有的方式進行改造,比如使用 Helm、Gitlab 等等。
另外如果你對聲明式的 Pipeline 比較熟悉的話,推薦使用這種方式來編寫 Jenkinsfile 文件,因爲使用聲明式的方式編寫的 Jenkinsfile 文件在 Blue Ocean 中不但支持得非常好,還可以直接在 Blue Ocean Editor 中可視化的對的 Pipeline 進行編輯操作,非常方便。