在持續佈署流程中,除了自動化佈署外,即時通知機制也至關重要。本文介紹如何將 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-loadermovies-parser
  • 使用preprod標籤來指定Docker映像。
  • 設定了環境變數AWS_REGIONSQS_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定義了兩個階段:CheckoutCopyDeploy 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預發布環境中。其他微服務也需要進行相同的更改,除了需要更新構建階段以注入適當的環境變數外。