在持續佈署流程中,除了自動化佈署外,即時通知機制也至關重要。本文介紹如何將 Jenkins 與 Slack 整合,以便在佈署過程中向團隊傳送通知。透過 Jenkins 的 Slack 外掛,可以輕鬆設定通知,並根據建置狀態自定義通知顏色和內容,例如顯示建置結果、提交作者和提交訊息等。此外,為了降低程式碼升級的風險,建立預發布環境是一個常見的作法。本文也將逐步說明如何建立預發布環境,並設定 Jenkins Pipeline,使其能夠自動將程式碼佈署到預發布環境。此流程包含設定預發布分支、Jenkins 憑證、修改 Jenkinsfile,以及更新佈署階段的條件判斷,以確保程式碼升級的穩定性和可靠性。
將Jenkins與Slack通知整合
當新的映像檔佈署到Docker Swarm後,開啟瀏覽器並導航至市場URL。它應該顯示歷史上IMDb前100名最佳電影,如圖10.28所示。
圖10.28 Watchlist市場儀錶板
這樣就達到了持續佈署的目標。然而,我們希望能夠在專案的佈署和CI/CD狀態發生變化時,通知開發團隊和產品團隊。
與Slack通知整合
在Pipeline的某些階段,您可能希望向團隊傳送Slack通知,以告知他們建置的狀態。要透過Jenkins傳送Slack訊息,我們需要提供一種方式,讓我們的作業能夠獲得Slack的授權。
幸運的是,Slack有一個預先建置的Jenkins整合,使得事情變得相當簡單。從http://mng.bz/xXOB安裝外掛。將WORKSPACE替換為您的Slack工作區名稱,如圖10.29所示。
圖10.29 Jenkins CI Slack整合
點選「Add to Slack」按鈕。然後選擇您希望Jenkins傳送通知的頻道,如圖10.30所示。
圖10.30 Slack頻道組態
之後,我們需要在Jenkins Slack通知外掛(https://plugins.jenkins.io/slack/)上設定組態,該外掛已經安裝在預先組態好的Jenkins主機映像檔上。輸入團隊工作區名稱、在Slack上建立的整合令牌,以及頻道名稱,如圖10.31所示,然後點選「Apply」和「Save」按鈕。
圖10.31 Jenkins Slack通知外掛
現在我們已經在Jenkins中正確組態了Slack,可以組態我們的CI/CDPipeline,以使用以下方法傳送通知來廣播建置狀態:
slackSend (color: colorCode, message: summary)
讓我們以movies-loader服務的CI/CDPipeline為例,在其末尾新增此指令;請參見以下清單。
node('workers'){
stage('Checkout'){}
stage('Unit Tests'){}
stage('Build'){}
stage('Push'){}
stage('Deploy'){}
slackSend (color: '#2e7d32',
message: "${env.JOB_NAME} has been successfully deployed")
}
清單10.18 Jenkins Slack外掛DSL
為了簡單起見,我省略了執行單元測試、建置映像檔以及將映像檔推播到登入檔的步驟。建議您將這些步驟放入我們即將探討的工作流程中。
將變更推播到功能分支,然後合併到develop分支。在Pipeline的末尾,將傳送一條新的Slack通知,如圖10.32所示。
圖10.32 Jenkins Slack通知
雖然這樣可以運作,但我們也希望在Pipeline失敗時收到通知。這就是try-catch區塊發揮作用的地方,用於處理Pipeline階段拋出的錯誤;請參見以下清單。
node('workers'){
try {
stage('Checkout'){
checkout scm
notifySlack('STARTED')
}
stage('Unit Tests'){}
stage('Build'){}
stage('Push'){}
stage('Deploy'){}
} catch(e){
currentBuild.result = 'FAILED'
throw e
} finally {
notifySlack(currentBuild.result)
}
}
這次,使用了notifySlack()方法,該方法根據Pipeline建置狀態傳送具有不同顏色的通知,如以下清單所示。
def notifySlack(String buildStatus){
buildStatus = buildStatus ?: 'SUCCESSFUL'
def colorCode = '#FF0000'
if (buildStatus == 'STARTED') {
colorCode = '#546e7a'
} else if (buildStatus == 'SUCCESSFUL') {
colorCode = '#2e7d32'
} else {
colorCode = '#c62828'
}
slackSend (color: colorCode,
message: "${env.JOB_NAME} build status: ${buildStatus}")
}
清單10.19 Slack通知在Jenkins中
根據您的建置結果,程式碼將傳送如圖10.33所示的Slack通知。
圖10.33 建置狀態通知
讓我們透過在Build階段新增以下指令來模擬建置失敗:
error "Build failed"
清單10.20 自定義Slack通知訊息顏色
將變更推播到GitHub。Pipeline將在Build階段失敗(圖10.34)。
圖10.34 在JenkinsPipeline中丟擲錯誤
在Slack頻道上,這次我們將收到一條建置狀態設定為「Failure」的通知,如圖10.35所示。
圖10.35 建置失敗的Slack通知
在以下清單中,我們將進一步擴充套件這一點。我們將在通知中新增更多資訊,例如推播事件的作者、Git提交ID和訊息。
def notifySlack(String buildStatus){
buildStatus = buildStatus ?: 'SUCCESSFUL'
def colorCode = '#FF0000'
def subject = "Name: '${env.JOB_NAME}'\nStatus: ${buildStatus}\nBuild ID: ${env.BUILD_NUMBER}"
def summary = "${subject}\nMessage: ${commitMessage()}\nAuthor: ${commitAuthor()}\nURL: ${env.BUILD_URL}"
if (buildStatus == 'STARTED') {
colorCode = '#546e7a'
} else if (buildStatus == 'SUCCESSFUL') {
colorCode = '#2e7d32'
} else {
colorCode = '#c62828'
}
slackSend (color: colorCode, message: summary)
}
清單10.21 自定義Slack通知訊息屬性
notifySlack()方法將呼叫commitAuthor()和commitMessage()以取得適當的資訊。 commitAuthor()方法將透過執行git show命令傳回提交作者的名稱,如以下清單所示。
def commitAuthor(){
sh 'git show -s --pretty=%an > .git/commitAuthor'
def commitAuthor = readFile('.git/commitAuthor').trim()
sh 'rm .git/commitAuthor'
commitAuthor
}
而commitMessage()方法將使用git log命令以及HEAD標誌來取得提交訊息描述;請參見以下清單。
def commitMessage() {
sh 'git log --format=%B -n 1 HEAD > .git/commitMessage'
def commitMessage = readFile('.git/commitMessage').trim()
sh 'rm .git/commitMessage'
commitMessage
}
清單10.22 Git輔助函式以取得作者
清單10.23 Git輔助函式以取得提交訊息
如果我們推播變更,在CI/CDPipeline的末尾,Slack通知應包含Jenkins作業名稱、建置ID及其狀態、作者名稱和提交描述,如圖10.36所示。
圖10.36 包含Git提交詳細資訊的Slack通知
圖表翻譯:
此圖示顯示了Jenkins與Slack通知整合的流程。首先,開發人員將程式碼變更推播到GitHub。然後,Jenkins檢測到變更並觸發CI/CDPipeline。在Pipeline的不同階段,Jenkins會向指定的Slack頻道傳送通知,報告建置的狀態。如果建置成功,將傳送成功通知;如果建置失敗,將傳送失敗通知,並包含相關的錯誤資訊。此外,通知還可能包含提交者的姓名、提交訊息和其他相關詳細資訊。
@startuml
skinparam backgroundColor #FEFEFE
title Jenkins Slack 整合與程式碼升級佈署
|開發者|
start
:提交程式碼;
:推送到 Git;
|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;
if (測試通過?) then (是)
:建置容器映像;
:推送到 Registry;
else (否)
:通知開發者;
stop
endif
|CD 系統|
:部署到測試環境;
:執行整合測試;
if (驗證通過?) then (是)
:部署到生產環境;
:健康檢查;
:完成部署;
else (否)
:回滾變更;
endif
stop
@enduml圖表翻譯: 此圖示展示了從開發人員推播程式碼變更到Jenkins傳送Slack通知的整個流程。它詳細說明瞭CI/CDPipeline的不同階段,以及根據建置結果傳送的不同型別的通知。
使用Jenkins處理程式碼升級
在多個Swarm叢集環境中進行程式碼升級時,維護多個環境可以避免在升級到生產環境時造成問題。同時,擁有類別似生產環境的環境,可以幫助您在不影響客戶的情況下,在預發布環境中執行應用程式的映象並重現問題。但這需要額外的成本。
建立預發布環境
建立一個新的Swarm叢集給預發布環境,可以在專用的預發布VPC中使用10.2.0.0/16CIDR區塊,或者將其佈署在與Jenkins相同的管理VPC中,如圖所示。
設定預發布分支
在watchlist-deployment GitHub儲存函式庫中建立一個名為preprod的分支,執行以下命令:
git checkout -b preprod
建立一個使用preprod標籤的docker-compose.yml檔案,並更新SQS URL以使用預發布佇列,如下所示。
version: "3.3"
services:
movies-loader:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-loader:preprod
environment:
- AWS_REGION=eu-west-3
- SQS_URL=https://sqs.REGION.amazonaws.com/ID/movies_to_parse_staging
movies-parser:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-parser:preprod
內容解密:
- 此
docker-compose.yml檔案定義了兩個服務:movies-loader和movies-parser。 - 使用
preprod標籤來指定Docker映像。 - 設定了環境變數
AWS_REGION和SQS_URL。
設定Jenkins憑證
建立一個名為swarm-staging的Jenkins憑證,型別為SSH使用者名稱與私鑰,使用佈署Swarm預發布叢集的SSH金鑰對。
建立Jenkinsfile
建立一個類別似於develop分支中的Jenkinsfile,更新swarmManager變數以指向預發布管理節點的IP或DNS記錄。同時更新SSH代理憑證以使用Swarm預發布憑證。
def swarmManager = 'manager.staging.domain.com'
def region = 'AWS REGION'
node('master'){
stage('Checkout'){
checkout scm
}
sshagent (credentials: ['swarm-staging']){
stage('Copy'){
sh "scp -o StrictHostKeyChecking=no docker-compose.yml ec2-user@${swarmManager}:/home/ec2-user"
}
stage('Deploy stack'){
sh "ssh -oStrictHostKeyChecking=no ec2-user@${swarmManager} '\$(\$(aws ecr get-login --no-include-email --region ${region}))' || true"
sh "ssh -oStrictHostKeyChecking=no ec2-user@${swarmManager} docker stack deploy --compose-file docker-compose.yml --with-registry-auth watchlist"
}
}
}
內容解密:
- 此Jenkinsfile定義了兩個階段:
Checkout、Copy和Deploy stack。 - 使用SSH代理憑證來複制
docker-compose.yml檔案到Swarm管理節點,並佈署堆積疊。 - 登入AWS ECR並使用Docker堆積疊佈署命令來佈署應用程式。
自動佈署到預發布環境
更新每個專案的Jenkinsfile,以觸發watchlist-deployment在預發布分支上的自動佈署。例如,對於movies-loader Jenkinsfile,構建並推播一個帶有preprod標籤的Docker映像。
stage('Push'){
sh "\$(aws ecr get-login --no-include-email --region ${region}) || true"
docker.withRegistry("https://${registry}") {
docker.image(imageName).push(commitID())
if (env.BRANCH_NAME == 'develop') {
docker.image(imageName).push('develop')
}
if (env.BRANCH_NAME == 'preprod') {
docker.image(imageName).push('preprod')
}
}
}
內容解密:
- 此階段登入AWS ECR,並將Docker映像推播到ECR。
- 根據目前的Git分支名稱,對Docker映像進行標記。
更新佈署階段
更新佈署階段的if子句條件,以觸發外部作業的佈署,如果分支名稱是預發布。
stage('Deploy'){
if(env.BRANCH_NAME == 'develop' || env.BRANCH_NAME == 'preprod'){
build job: "watchlist-deployment/${env.BRANCH_NAME}"
}
}
內容解密:
- 此階段根據目前的分支名稱來觸發外部作業的佈署。
結果
當合併發生時,將在預發布分支上觸發新的構建,並且應用程式堆積疊將被佈署到Swarm預發布環境中。其他微服務也需要進行相同的更改,除了需要更新構建階段以注入適當的環境變數外。