返回文章列表

藍綠佈署自動化流程詳解

本文探討藍綠佈署的自動化流程,使用 Jenkins Workflow DSL 結合 Groovy

Web 開發 DevOps

藍綠佈署策略的核心在於維護兩個相同的生產環境,透過切換流量來實作不停機佈署。本文介紹的自動化流程,利用 Jenkins 和 Docker Compose 協調容器,並結合 Consul 進行服務發現和組態管理,最後透過 Nginx 作為反向代理實作流量切換。此流程確保在新版本佈署過程中,服務始終保持可用狀態,有效降低了佈署風險。文章中提供的 Groovy 指令碼示例,清晰地展示了自動化流程的各個步驟,並詳細解釋了每個步驟的具體操作和作用,方便讀者理解和應用。此外,文章還提供了手動驗證佈署結果的方法,可以幫助工程師快速確認佈署是否成功,以及服務是否正常執行。

藍綠佈署(Blue-Green Deployment)自動化流程詳解

藍綠佈署是一種無停機時間的佈署策略,透過執行兩個相同的生產環境(藍色和綠色)來實作零宕機佈署。本文將探討藍綠佈署的手動流程和自動化實作。

手動藍綠佈署流程

手動藍綠佈署涉及多個步驟,包括取得服務的當前顏色、提取新版本的服務、更新代理組態等。以下是手動流程的關鍵步驟:

  1. 取得下一個顏色:使用指令碼 ./get-color.sh 取得下一個顏色。

    NEXT_COLOR=`./get-color.sh books-ms prod`
    
  2. 提取並啟動新版本服務:使用 Docker Compose 提取並啟動新版本的服務。

    docker-compose pull app-$NEXT_COLOR
    docker-compose up -d app-$NEXT_COLOR
    
  3. 取得新版本服務的埠:使用指令碼 ./get-port.sh 取得新版本服務的埠。

    NEXT_PORT=`./get-port.sh books-ms prod $NEXT_COLOR`
    
  4. 測試新版本服務:在將新版本服務與代理整合之前進行測試。

    curl -I prod:$NEXT_PORT/api/v1/books
    
  5. 更新代理組態:使用 consul-template 更新代理組態。

    consul-template \
      -consul prod:8500 \
      -template "nginx-upstreams-$NEXT_COLOR.ctmpl:nginx-upstreams.conf" \
      -once
    scp nginx-upstreams.conf prod:/data/nginx/upstreams/books-ms.conf
    docker kill -s HUP nginx
    
  6. 測試整合後的服務:測試透過代理存取新版本服務。

    curl -I prod/api/v1/books
    
  7. 更新 Consul 中的顏色並停止舊版本服務:將新顏色更新到 Consul 並停止舊版本服務。

    curl -X PUT -d $NEXT_COLOR prod:8500/v1/kv/books-ms/color
    CURR_COLOR=`./get-color.sh books-ms prod`
    docker-compose stop app-$CURR_COLOR
    

手動流程的程式碼解密:

  • ./get-color.sh./get-port.sh 指令碼用於取得當前或下一個顏色以及服務的埠號,這些指令碼與 Consul 互動以檢索必要的資訊。
  • docker-compose 命令用於管理服務的生命週期,包括提取、啟動和停止服務容器。
  • consul-template 用於根據 Consul 中的資料生成組態檔案,從而更新代理組態。
  • curl 命令用於測試服務的可用性和正確性。

自動化藍綠佈署

為了簡化藍綠佈署流程,我們使用 Jenkins 進行自動化。Jenkins Workflow 提供了靈活的方式來定義複雜的工作流程。

Jenkinsfile 解讀:

node("cd") {
    def serviceName = "books-ms"
    def prodIp = "10.100.198.201"
    def proxyIp = "10.100.198.201"
    def proxyNode = "prod"
    def registryIpPort = "10.100.198.200:5000"

    def flow = load "/data/scripts/workflow-util.groovy"

    git url: "https://github.com/vfarcic/${serviceName}.git"
    flow.provision("prod2.yml")
    flow.buildTests(serviceName, registryIpPort)
    flow.runTests(serviceName, "tests", "")
    flow.buildService(serviceName, registryIpPort)

    def currentColor = flow.getCurrentColor(serviceName, prodIp)
    def nextColor = flow.getNextColor(currentColor)

    flow.deployBG(serviceName, prodIp, nextColor)
    flow.runBGPreIntegrationTests(serviceName, prodIp, nextColor)
    flow.updateBGProxy(serviceName, proxyNode, nextColor)
    flow.runBGPostIntegrationTests(serviceName, prodIp, proxyIp, proxyNode, currentColor, nextColor)
}

自動化流程的程式碼解密:

  • node("cd") 指定了執行 Workflow 的節點。
  • flow 物件透過載入 workflow-util.groovy 指令碼獲得,該指令碼封裝了多個用於自動化藍綠佈署的函式,如 deployBGrunBGPreIntegrationTests 等。
  • 自動化流程涵蓋了從程式碼簽出、構建、測試到佈署和驗證的全過程。

Blue-Green Deployment 實作詳解

Blue-Green Deployment是一種降低軟體佈署風險的策略,透過在兩個相同的生產環境(藍色和綠色)之間切換,以實作零停機時間的更新。以下將探討其實作細節。

佈署流程指令碼解析

首先,我們來分析佈署流程的Groovy指令碼。該指令碼首先宣告了一些變數,接著載入了workflow-util.groovy指令碼。這個指令碼包含了許多實用的函式,例如環境準備、建置、測試等。

取得目前與下一個佈署顏色

指令碼中使用了兩個關鍵函式:getCurrentColorgetNextColor。這兩個函式的實作如下:

def getCurrentColor(serviceName, prodIp) {
    try {
        return sendHttpRequest("http://${prodIp}:8500/v1/kv/${serviceName}/color?raw")
    } catch(e) {
        return ""
    }
}

def getNextColor(currentColor) {
    if (currentColor == "blue") {
        return "green"
    } else {
        return "blue"
    }
}

內容解密:

  1. getCurrentColor函式:此函式透過向Consul傳送HTTP請求來取得目前的佈署顏色。如果請求失敗,則傳回空字串。
  2. getNextColor函式:根據目前的佈署顏色,決定下一個佈署顏色。如果目前是藍色,則下一個是綠色,反之亦然。

佈署新版本

一旦我們知道了目前和下一個佈署顏色,就可以呼叫deployBG函式來佈署新版本:

def deployBG(serviceName, prodIp, color) {
    stage "Deploy"
    withEnv(["DOCKER_HOST=tcp://${prodIp}:2375"]) {
        sh "docker-compose pull app-${color}"
        sh "docker-compose -p ${serviceName} up -d app-${color}"
    }
}

內容解密:

  1. 設定DOCKER_HOST環境變數:指定Docker CLI連線到生產節點上的Docker守護程式。
  2. 提取最新映像並啟動服務:使用Docker Compose提取最新的映像並在後台啟動對應顏色的服務。

執行預整合測試

新版本佈署後,但尚未與代理服務整合前,我們執行預整合測試:

def runBGPreIntegrationTests(serviceName, prodIp, color) {
    stage "Run pre-integration tests"
    def address = getAddress(serviceName, prodIp, color)
    try {
        runTests(serviceName, "integ", "-e DOMAIN=http://${address}")
    } catch(e) {
        stopBG(serviceName, prodIp, color);
        error("Pre-integration tests failed")
    }
}

內容解密:

  1. 取得新佈署服務的地址:透過getAddress函式從Consul取得新佈署服務的地址。
  2. 執行測試:使用取得的地址作為環境變數DOMAIN來執行測試。如果測試失敗,則停止新佈署的服務並報告錯誤。

更新代理服務

預整合測試透過後,我們更新代理服務以使新版本可供使用者存取:

def updateBGProxy(serviceName, proxyNode, color) {
    stage "Update proxy"
    stash includes: 'nginx-*', name: 'nginx'
    node(proxyNode) {
        unstash 'nginx'
        sh "sudo cp nginx-includes.conf /data/nginx/includes/${serviceName}.conf"
        sh "sudo consul-template \
            -consul localhost:8500 \
            -template \"nginx-upstreams-${color}.ctmpl:/data/nginx/upstreams/${serviceName}.conf:docker kill -s HUP nginx\" \
            -once"
        sh "curl -X PUT -d ${color} http://localhost:8500/v1/kv/${serviceName}/color"
    }
}

內容解密:

  1. 使用consul-template更新Nginx組態:根據佈署顏色選擇對應的範本檔案來更新Nginx的上游組態。
  2. 更新Consul中的顏色記錄:將新的佈署顏色儲存到Consul中。

執行後整合測試

最後,我們執行後整合測試以確認代理服務更新正確:

def runBGPostIntegrationTests(serviceName, prodIp, proxyIp, proxyNode, currentColor, nextColor) {
    stage "Run post-integration tests"
    try {
        runTests(serviceName, "integ", "-e DOMAIN=http://${proxyIp}")
    } catch(e) {
        if (currentColor != "") {
            updateBGProxy(serviceName, proxyNode, currentColor)
        }
        stopBG(serviceName, prodIp, nextColor);
        error("Post-integration tests failed")
    }
    stopBG(serviceName, prodIp, currentColor);
}

內容解密:

  1. 執行測試:透過代理服務的IP地址執行測試。
  2. 錯誤處理:如果測試失敗,則回復到之前的版本並停止當前版本。

藍綠佈署(Blue-Green Deployment)詳解與實作驗證

藍綠佈署是一種在不影響現有服務的前提下,實作零停機佈署的策略。該方法涉及兩個相同的生產環境,分別稱為藍色環境和綠色環境。某一時刻,只有其中一個環境處於活躍狀態並對外提供服務。

藍綠佈署流程自動化實作

以下是一個使用 Groovy 指令碼結合 Jenkins Workflow DSL 實作藍綠佈署自動化的例子:

// 藍綠佈署指令碼示例
node("master") {
    // 定義變數
    def currentColor = getCurrentColor()
    def nextColor = (currentColor == "blue") ? "green" : "blue"

    // 佈署新版本
    deployNewRelease(nextColor)

    // 執行整合測試
    if (!runIntegrationTests()) {
        // 測試失敗,回復變更
        updateBGProxy(currentColor)
        stopBG(nextColor)
    } else {
        // 測試透過,停止舊版本
        stopBG(currentColor)
    }
}

// 取得當前顏色
def getCurrentColor() {
    // 從 Consul 取得當前顏色
    def response = sh(returnStdout: true, script: "curl prod:8500/v1/kv/books-ms/color?raw")
    return response.trim()
}

// 佈署新版本到指定顏色環境
def deployNewRelease(color) {
    // 佈署邏輯
}

// 更新 nginx 組態以指向指定顏色環境
def updateBGProxy(color) {
    // 更新 nginx 組態邏輯
}

// 停止指定顏色環境
def stopBG(color) {
    // 停止容器邏輯
}

// 執行整合測試
def runIntegrationTests() {
    // 測試邏輯
    return true // 或 false,根據測試結果
}

內容解密:

  1. getCurrentColor 方法:透過查詢 Consul 的 KV 儲存,取得當前活躍環境的顏色。
  2. deployNewRelease 方法:將新版本佈署到下一個顏色所代表的環境中。
  3. updateBGProxy 方法:更新 nginx 組態,使其指向指定的顏色環境,用於回復或切換服務。
  4. stopBG 方法:停止指定顏色環境中的容器,釋放資源。
  5. runIntegrationTests 方法:執行整合測試,驗證新版本佈署的正確性。

手動驗證藍綠佈署結果

在完成自動化佈署後,可以透過以下步驟手動驗證結果:

  1. 檢查容器狀態

    export DOCKER_HOST=tcp://prod:2375
    docker ps -a --filter name=books --format "table {{.Names}}"
    

    該命令用於篩選並格式化輸出名稱包含 “books” 的容器。

  2. 查詢 Consul 中的服務註冊資訊

    curl prod:8500/v1/catalog/services | jq '.'
    curl prod:8500/v1/catalog/service/books-ms-blue | jq '.'
    

    驗證服務是否正確註冊到 Consul。

  3. 檢查當前活躍環境顏色

    curl prod:8500/v1/kv/books-ms/color?raw
    

    該命令傳回當前活躍環境的顏色。

  4. 驗證服務可用性

    curl -I prod/api/v1/books
    

    檢查透過 nginx 代理存取服務的狀態碼,確認服務正常執行。

重複執行與驗證

重複執行藍綠佈署作業,並觀察以下變化:

  • 容器名稱與狀態的切換(藍色與綠色環境的切換)。
  • Consul 中服務註冊資訊與當前顏色值的更新。
  • 服務始終透過 nginx 代理保持可用,無停機時間。