使用Helm優化Kubernetes下的研發體驗:實現持續交付流水線
【編者的話】在上一篇的基礎上,筆者將詳細介紹如果通過Pipeline As Code的方式實現Helm下的端到端交付過程。
接著上一篇《使用Helm優化Kubernetes下的研發體驗:基礎設施即程式碼》中筆者介紹瞭如何在專案中使用Helm,在專案原始碼中,我們通過Dockerfile定義了專案是如何構建的,使用Helm定義了專案是如何部署的。 團隊中的任何人員(角色)在獲取原始碼的同時就已經具備了一鍵構建,一鍵部署的能力。
整體目標
在這一篇中,我們將使用Jenkins在此基礎上構建一條完整的持續交付流水線,並且讓團隊不同成員能夠基於該流水線展開基本的協作。
- 開發: 持續提交程式碼並能夠通過持續整合(CI)過程快速獲取反饋,在通過CI驗證後,能夠自動化部署到開發環境,以便後續的進一步功能測試(手動/自動自動化測試)等;
- 測試: 在需要對專案功能進行驗證時,可以一鍵部署測試環境,並且在此環境基礎上可以完成功能驗收(手動),以及全量的自動化驗收測試等;
- 運維:一鍵部署生產環境,同時釋出建立版本,以便在釋出異常時能夠快速回歸

資料來源: ofollow,noindex" target="_blank">https://dzone.com/articles/eas ... ns-he
示例專案的程式碼可以從 Github 下載,示例專案為 containerization-spring-with-helm
。接下來,我們將分階段介紹如何通過 Jenkinsfile 定義整個過程。

專案構建階段
當前階段Jenkinsfile定義如下:
stage('Build And Test') { steps { dir('containerization-spring-with-helm') { sh 'docker build -t yunlzheng/spring-sample:$GIT_COMMIT .' } } }
在 Build And Test
階段,我們直接通過原始碼中的Dockerfile定義了整個持續整合階段的任務,通過docker的 Multi-Stage Builds
特性,持續整合的所有任務全部通過Dockerfile進行定義,這樣無論是在本地還是持續整合伺服器中,我們都可以非常方便的進行執行CI任務。

釋出映象和Helm階段
當前階段Jenkinsfile定義如下:
stage('Publish Docker And Helm') { steps { withDockerRegistry([credentialsId: 'dockerhub', url: '']) { sh 'docker push yunlzheng/spring-sample:$GIT_COMMIT' } script { def filename = 'containerization-spring-with-helm/chart/values.yaml' def data = readYaml file: filename data.image.tag = env.GIT_COMMIT sh "rm $filename" writeYaml file: filename, data: data } script { def filename = 'containerization-spring-with-helm/chart/Chart.yaml' def data = readYaml file: filename data.version = env.GIT_COMMIT sh "rm $filename" writeYaml file: filename, data: data } dir('containerization-spring-with-helm') { sh 'helm push chart https://repomanage.rdc.aliyun.com/helm_repositories/26125-play-helm --username=$HELM_USERNAME --password=$HELM_PASSWORD--version=$GIT_COMMIT' } } }
Push映象
通過 withDockerRegistry
的上下文中,Jenkins會確保docker client首先通過 credentials dockerhub
中定義的使用者名稱和密碼完成登入後,在執行 docker push
任務。並且我們確保使用當前程式碼版本的COMMIT_ID作為映象的Tag,從而將Docker映象版本與原始碼版本進行一一對應;
重寫Chart映象版本
通過 readYaml
讀取chart的values.yaml內容到變數data後,通過 writeYaml
重寫values.yaml中的映象tag版本與當前構建映象版本一致;
重寫Chart版本
與映象一樣,我們希望Chart的版本與原始碼版本能夠一一對應;
上傳Chart
這裡我們直接使用 阿里雲效 提供的Helm倉庫服務, 點選開通私有倉庫服務 。通過Helm Push外掛釋出Chart到Helm倉庫。
其中環境變數 $HELM_USERNAME
和 $HELM_PASSWORD
是通過jenkins的Credentials載入到環境變數中:
environment { HELM_USERNAME = credentials('HELM_USERNAME') HELM_PASSWORD = credentials('HELM_PASSWORD') }

部署到開發/測試環境階段
當前階段Jenkinsfile定義如下:
stage('Deploy To Dev') { steps { dir('containerization-spring-with-helm') { dir('chart') { sh 'helm upgrade spring-app-dev --install --namespace=dev --set ingress.host=dev.spring-example.local .' } } } } stage('Deploy To Stageing') { steps { input 'Do you approve staging?' dir('containerization-spring-with-helm') { dir('chart') { sh 'helm upgrade spring-app-staging --install --namespace=staging --set ingress.host=staging.spring-example.local .' } } } }
在Jenkinsfile中我們分別定義了兩個階段 Deploy To Dev
和 Deploy To Stageing
。我們通過Kubernetes的名稱空間劃分單獨的開發環境和測試環境。並且通過覆蓋ingress.host確保能夠通過ingress域名 dev.spring-example.local
和 staging.spring-example.local
訪問到不同環境。 對於Staging環境而言,通過 input
確保該流程一定是通過人工確認的。
通過 helm upgrade
命令可以確保在特定名稱空間下部署或者升級已有的Chart:
helm upgrade spring-app-staging --install --namespace=staging --set ingress.host=staging.spring-example.local .


部署到生產環境階段
當前階段Jenkinsfile定義如下:
stage('Deploy To Production') { steps { input 'Do you approve production?' script { env.RELEASE = input message: 'Please input the release version', ok: 'Deploy', parameters: [ [$class: 'TextParameterDefinition', defaultValue: '0.0.1', description: 'Cureent release version', name: 'release'] ] } echo 'Deploy and release: $RELEASE' script { def filename = 'containerization-spring-with-helm/chart/Chart.yaml' def data = readYaml file: filename data.version = env.RELEASE sh "rm $filename" writeYaml file: filename, data: data } dir('containerization-spring-with-helm') { dir('chart') { sh 'helm lint' sh 'helm upgrade spring-app-prod --install --namespace=production --set ingress.host=production.spring-example.local .' } sh 'helm push chart https://repomanage.rdc.aliyun.com/helm_repositories/26125-play-helm --username=$HELM_USERNAME --password=$HELM_PASSWORD--version=$RELEASE' } } }
在最後一個 Deploy To Production
階段中,與Dev和Stageing的部署不同在於當人工確認部署測試環境之後,我們需要使用者手動輸入當前釋出的版本,以確保對當前釋出的Chart版本能完成一個基線的定義:

這裡,我們需要確保當前定義的版本是符合Sem規範的,因此這裡使用了 helm lint
對Chart定義進行校驗。
小結
通過程式碼提交版本(COMMIT_ID)關聯了原始碼版本,映象版本以及Chart版本。同時對於正式釋出的軟體版本而言,單獨定義了正式釋出的版本號。對於實踐持續交付的研發團隊而言,我們可以通過上述一條流水線基本實現軟體交付的整個生命週期。而對於傳統交付模式的團隊,則可以通過將上述過程分拆到多條流水線(開發流水線,測試流水線,釋出流水線)來適應自己的釋出模式。
回到我們的總體目標而言,通過基礎設施及程式碼的方式,我們定義了一個相對完備且自描述的應用。通過流水線即程式碼的方式,定義了應用的端到端交付過程。通過Docker定義專案的構建過程,通過Helm實現Kubernetes下應用的釋出管理,通過Jenkinsfile定義了軟體的整個交付過程,並且不同職能的團隊成員,可以方便的在此基礎上實現協作。最後借用《持續交付》的話“提前並頻繁地做讓你感到痛苦的事!“ ,希望大家都能夠Happy Coding。