Kubernetes 提供 Rolling Updates、Blue/Green Deployments 和 Canary Deployments 等佈署策略,讓開發者能根據應用程式特性選擇最合適的更新方式。Rolling Updates 能夠不停機更新,Blue/Green Deployments 則提供快速回復機制,而 Canary Deployments 則允許逐步釋出新版本以降低風險。本文將詳細介紹這些佈署策略的實作方式,並說明如何結合 CI/CD Pipeline 和混沌工程,開發更強健的應用程式。實務上,會使用 Drone CI 作為 CI/CD 工具,並透過 kubectl 與 Kubernetes 叢集互動,設定 Service Account、ClusterRoleBinding、Token 和證書等必要元件。此外,文章也提供 Drone Pipeline 的 YAML 設定範例,涵蓋編譯、測試、釋出和佈署等階段,並示範如何使用 Chaos Toolkit 進行混沌實驗,驗證應用程式的容錯能力。最後,文章總結了 CI/CD 的最佳實踐,例如自動化、可靠的測試、Pipeline as Code、Docker 映象最佳化、版本標籤管理,以及逐步採用更進階的佈署策略和生產環境測試。

持續佈署與 Kubernetes 佈署策略

在軟體開發的流程中,持續佈署(Continuous Deployment, CD)扮演著至關重要的角色。持續佈署是一種自動化的過程,當程式碼透過持續整合(Continuous Integration, CI)流程後,會自動佈署到生產環境,無需人工干預。容器技術在此過程中提供了極大的便利,因為容器映像(Container Image)是不可變的,可以在不同環境中保持一致。

為什麼需要堅實的 CI 流程?

在進行持續佈署之前,必須先建立一個堅實的 CI 流程。如果沒有一套健全的測試機制,很容易將有問題的程式碼滾動到所有環境中。因此,CI 流程是持續佈署的基礎。

佈署策略

Kubernetes 提供了多種佈署策略,讓開發者可以根據需求選擇適合的更新方式。以下是三種常見的佈署策略:

  1. 滾動更新(Rolling Updates)

    • Kubernetes 內建支援滾動更新,可以在不造成停機的情況下更新應用程式。
    • 開發者可以設定 maxSurgemaxUnavailable 引數來控制更新過程中的副本數量。
    • kind: Deployment
      apiVersion: apps/v1
      metadata:
        name: frontend
        labels:
          app: frontend
      spec:
        replicas: 3
        selector:
          matchLabels:
            app: frontend
        template:
          metadata:
            labels:
              app: frontend
          spec:
            containers:
            - name: frontend
              image: brendanburns/frontend:v1
        strategy:
          type: RollingUpdate
          rollingUpdate:
            maxSurge: 1
            maxUnavailable: 1
      
    • 內容解密:

      • maxSurge 指定了在滾動更新過程中,可以超出預期副本數量的最大數量。
      • maxUnavailable 指定了在滾動更新過程中,不可用的副本的最大數量。
      • 這兩個引數共同控制了滾動更新的節奏,以確保服務的連續性。
  2. 藍綠佈署(Blue/Green Deployments)

    • 藍綠佈署允許開發者以可預測的方式發布新版本的應用程式。
    • 這種方式需要同時佈署舊版本和新版本的環境,因此需要額外的資源。
    • 藍綠佈署的一個主要優點是,可以輕易地切換回舊版本。
      • 此圖示展示了藍綠佈署的流程,其中流量可以根據需要切換回舊版本或繼續使用新版本。
  3. 金絲雀佈署(Canary Deployments)

    • 金絲雀佈署是一種將新版本的應用程式逐步發布給一部分使用者的策略。
    • 這種方式可以降低發布新版本的風險,因為只有少量的使用者會受到影響。

就緒探針與生命週期鉤子

在進行滾動更新時,為了避免連線中斷,可以使用就緒探針(Readiness Probe)和生命週期鉤子(Lifecycle Hook)。

  • 就緒探針確保新的副本已經準備好接受流量。
  • 生命週期鉤子可以在容器終止前執行特定的命令,以確保連線被正常關閉。
kind: Deployment
apiVersion: apps/v1
metadata:
  name: frontend
  labels:
    app: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: brendanburns/frontend:v1
        readinessProbe:
          httpGet:
            path: /readiness
            port: 8888
        lifecycle:
          preStop:
            exec:
              command: ["/usr/sbin/nginx","-s","quit"]

內容解密:

  • readinessProbe 用於檢查容器是否準備好接受流量。
  • lifecycle.preStop 鉤子在容器終止前執行指定的命令,以優雅地關閉 NGINX。

金絲雀佈署(Canary Deployments)與生產環境測試

金絲雀佈署的優勢與實作

金絲雀佈署與藍綠佈署(Blue/Green Deployments)類別似,但提供了更精細的流量控制。現代Ingress實作通常支援將一定比例的流量導向新版本,也可透過服務網格技術(如Istio、Linkerd或HashiCorp Consul)來實作此佈署策略。

金絲雀佈署允許對部分使用者測試新功能。例如,將新版本應用程式佈署後,只對10%的使用者開放。若無錯誤,則逐步增加新版本的流量比例。此外,還可針對特定區域或使用者群體進行測試,這類別發布常被稱為A/B測試或暗黑發布(Dark Releases)。

金絲雀佈署的考量因素

  1. 能夠將部分流量導向新版本
  2. 對穩態(Steady State)有深入瞭解,以便與新版本進行比較
  3. 具備評估新版本狀態的指標

圖示說明

此圖示呈現金絲雀佈署的架構:

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Kubernetes 佈署策略與混沌工程實踐

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

此圖示展示了金絲雀佈署如何將流量分配至新舊版本,並共用相同的資料函式庫。

內容解密:

此圖示說明金絲雀佈署的基本架構。其中90%的流量導向舊版本,10%導向新版本,兩者共用同一資料函式庫。此設計需確保資料函式庫結構相容於兩種版本,以避免相容性問題。

生產環境測試的重要性

在生產環境中進行測試有助於提升應用程式的可靠性、擴充套件性和使用者經驗(UX)。儘管存在風險,但透過完善的可觀測性策略和自動化工具,可以有效降低風險。

生產環境測試的工具與技術

  1. 金絲雀佈署
  2. 藍綠佈署
  3. 流量轉移
  4. 特徵標誌(Feature Flags)
  5. 混沌工程(Chaos Engineering)
  6. 分散式追蹤(Distributed Tracing)
  7. 儀表化(Instrumentation)
  8. 流量映象(Traffic Shadowing)

混沌工程的實作步驟

  1. 建立假設並瞭解系統的穩態
  2. 模擬真實世界的事件
  3. 建立對照組和實驗組進行比較
  4. 執行實驗以驗證假設

內容解密:

混沌工程是一種在生產環境中進行實驗以發現系統弱點的方法。透過上述步驟,可以系統性地測試系統的韌性,並在最小化影響範圍的前提下進行實驗。

設定CI/CD Pipeline與執行混沌實驗

首先,需Fork一個GitHub儲存函式庫以供後續操作使用。接著,設定Drone CI並註冊相關憑證,包括Docker Hub和Kubernetes叢集的認證資訊。

Drone CI設定步驟

  1. 登入Drone並啟用Fork的儲存函式庫
  2. 在儲存函式庫設定中新增必要的Secrets,包括Docker Hub的使用者名稱和密碼,以及Kubernetes叢集的API端點、憑證和Token
程式碼範例:新增Secrets至Drone CI
# .drone.yml 範例片段
secrets:
  - docker_username
  - docker_password
  - kubernetes_server
  - kubernetes_cert
  - kubernetes_token

內容解密:

此YAML檔案片段定義了Drone CI所需的Secrets,用於存取Docker Hub和Kubernetes叢集。正確設定這些Secrets是實作自動化CI/CD流程的關鍵步驟。Secrets包括Docker Hub的使用者名稱和密碼,用於推播映像;以及Kubernetes叢集的API端點、憑證和Token,用於佈署應用程式至叢集。

建立 CI/CD Pipeline 與執行混沌實驗

取得 Kubernetes API 端點

首先,您需要取得 Kubernetes API 端點,可以透過以下指令來取得:

kubectl cluster-info

執行後,您將看到類別似以下的輸出:Kubernetes master is running at https://kbp.centralus.azmk8s.io:443。請將此 URL 儲存於 kubernetes_server 這個 secret 中。

建立 Service Account

接下來,建立一個 Service Account,讓 Drone 能夠連線到 Kubernetes 叢集。使用以下指令建立 Service Account:

kubectl create serviceaccount drone

內容解密:

  • kubectl create serviceaccount drone:此指令用於在 Kubernetes 中建立一個名為 drone 的 Service Account,讓 Drone 能夠以此身份與 Kubernetes 叢集互動。

建立 ClusterRoleBinding

使用以下指令為剛才建立的 Service Account 建立 ClusterRoleBinding:

kubectl create clusterrolebinding drone-admin \
--clusterrole=cluster-admin \
--serviceaccount=default:drone

內容解密:

  • kubectl create clusterrolebinding drone-admin:此指令建立了一個名為 drone-admin 的 ClusterRoleBinding。
  • --clusterrole=cluster-admin:指定了要繫結的 ClusterRole 為 cluster-admin,賦予最高的管理許可權。
  • --serviceaccount=default:drone:指定了要繫結的 Service Account 為 default namespace 下的 drone

取得 Service Account Token

接著,取得 Service Account 的 Token:

TOKENNAME=`kubectl -n default get serviceaccount/drone -o jsonpath='{.secrets[0].name}'`
TOKEN=`kubectl -n default get secret $TOKENNAME -o jsonpath='{.data.token}' | base64 -d`
echo $TOKEN

請將輸出的 Token 儲存於 kubernetes_token 這個 secret 中。

內容解密:

  • TOKENNAME=kubectl -n default get serviceaccount/drone -o jsonpath=’{.secrets[0].name}’``:取得與 drone Service Account 相關聯的 Secret 名稱。
  • TOKEN=kubectl -n default get secret $TOKENNAME -o jsonpath=’{.data.token}’ | base64 -d``:從該 Secret 中提取 Token,並進行 base64 解碼。
  • echo $TOKEN:輸出解碼後的 Token。

取得 User Certificate

您還需要 User Certificate 來驗證叢集身份。使用以下指令並將輸出的 ca.crt 內容儲存於 kubernetes_cert 這個 secret 中:

kubectl get secret $TOKENNAME -o yaml | grep 'ca.crt:'

內容解密:

  • kubectl get secret $TOKENNAME -o yaml:以 YAML 格式輸出指定 Secret 的詳細資訊。
  • grep 'ca.crt:':過濾出包含 ca.crt: 的行,該行包含了叢集的 CA 證書。

建立 Drone Pipeline

現在,您可以在 Drone 中建立一個 Pipeline,先編譯您的應用程式,然後推播到 Docker Hub。

編譯步驟

pipeline:
  build:
    image: node
    commands:
      - cd frontend
      - npm i redis --save

內容解密:

  • image: node:使用官方的 Node.js 映象來執行編譯步驟。
  • commands:在容器中執行的指令列表。
    • cd frontend:切換到前端應用程式目錄。
    • npm i redis --save:安裝 Redis 套件並儲存於 package.json

測試步驟

test:
  image: node
  commands:
    - cd frontend
    - npm i redis --save
    - npm test

內容解密:

  • 與編譯步驟類別似,但額外執行了 npm test 以執行測試。

釋出步驟

publish:
  image: plugins/docker
  dockerfile: ./frontend/Dockerfile
  context: ./frontend
  repo: dstrebel/frontend
  tags: [latest, v2]
  secrets: [docker_username, docker_password]

內容解密:

  • image: plugins/docker:使用 Docker Plugin 映象來構建並推播 Docker 映象。
  • dockerfilecontext:指定 Dockerfile 的位置和構建上下文。
  • repo:指定要推播的 Docker Hub 倉函式庫。
  • tags:為映象加上標籤。
  • secrets:參照包含 Docker Hub 登入資訊的 Secret。

設定 CD(持續佈署)

在 Pipeline 中加入佈署步驟,將應用程式佈署到 Kubernetes 叢集:

kubectl:
  image: dstrebel/drone-kubectl-helm
  secrets: [kubernetes_server, kubernetes_cert, kubernetes_token]
  kubectl: "apply -f ./frontend/deployment.yaml"

內容解密:

  • image: dstrebel/drone-kubectl-helm:使用包含 kubectl 和 Helm 的映象。
  • secrets:參照包含 Kubernetes 連線資訊的 Secret。
  • kubectl: "apply -f ./frontend/deployment.yaml":執行 kubectl apply 指令以佈署應用程式。

確認佈署狀態

佈署完成後,可以檢查 Pod 狀態:

kubectl get pods

或者,在 Drone Pipeline 中加入測試佈署的步驟:

test-deployment:
  image: dstrebel/drone-kubectl-helm
  secrets: [kubernetes_server, kubernetes_cert, kubernetes_token]
  kubectl: "get deployment frontend"

內容解密:

  • 此步驟檢查名為 frontend 的 Deployment 狀態。

滾動更新(Rolling Update)

修改前端程式碼後提交變更,觸發滾動更新。Kubernetes 將逐步替換舊的 Pod。

簡單混沌實驗(Chaos Experiment)

使用 Chaos Toolkit 自動終止 Pod,以測試應用程式的韌性。

pip install -U chaostoolkit
pip install chaostoolkit-kubernetes
export FRONTEND_URL="http://$(kubectl get svc frontend -o jsonpath="{.status.loadBalancer.ingress[*].ip}"):8080/api/"
chaos run experiment.json

內容解密:

  • 安裝 Chaos Toolkit 和 Kubernetes 相關外掛。
  • 設定前端服務 URL。
  • 執行混沌實驗。

CI/CD 最佳實踐

  • 重點關注自動化和提供快速構建,以給開發者快速回饋。
  • 提供可靠的測試,以確保程式碼品質。
  • 將 Pipeline 定義為程式碼,以便進行版本控制。
  • 最佳化 Docker 映象大小和安全性。
  • 使用有意義的標籤而非「latest」。
  • 從滾動更新開始,逐步嘗試藍綠佈署和金絲雀發布等策略。
  • 在生產環境中進行測試,以提高可靠性。