在 GKE 上部署 Redis 叢集

本教學課程提供建議做法,說明如何建立有狀態的應用程式,以及升級執行該應用程式的 Google Kubernetes Engine (GKE) 叢集。本教學課程以 Redis 為例,說明如何部署有狀態應用程式,但相同概念也適用於部署在 GKE 的其他類型有狀態應用程式。

建立已註冊發布版本的 GKE 叢集

如要建立 GKE 叢集,請完成下列步驟:

  1. 建立名為 redis-test 的叢集,其中包含三個節點:

    gcloud container clusters create redis-test \
        --location CONTROL_PLANE_LOCATION \
        --num-nodes=3 \
        --release-channel regular
    

    CONTROL_PLANE_LOCATION 替換為叢集控制層的 Compute Engine 位置。為地區叢集提供地區,或為區域叢集提供區域。

    叢集建立完成後,您應該會看到類似以下範例的輸出內容:

      NAME: redis-test
      LOCATION: us-central1-c
      MASTER_VERSION: 1.22.10-gke.600
      MASTER_IP: 34.69.67.7
      MACHINE_TYPE: e2-medium
      NODE_VERSION: 1.22.10-gke.600
      NUM_NODES: 3
      STATUS: RUNNING
    
  2. 設定 kubectl 與叢集通訊:

    gcloud container clusters get-credentials redis-test
    

在 GKE 上建立 Redis 叢集

在本節中,您將部署 ConfigMapStatefulSet無標題服務,在先前建立的 GKE 叢集上新增 Redis 叢集。

如要建立 Redis 叢集,請完成下列步驟:

  1. 請參閱儲存 Redis 設定的 ConfigMap 檔案 (redis-configmap.yaml)。以下程式碼片段顯示 Readiness 探測和 Liveness 探測指令碼。

    readiness.sh: |-
      #!/bin/sh
    
      pingResponse="$(redis-cli -h localhost ping)"
      if [ "$?" -eq "124" ]; then
        echo "PING timed out"
        exit 1
      fi
    
      if [ "$pingResponse" != "PONG"]; then
        echo "$pingResponse"
        exit 1
      fi
    liveness.sh: |-
      #!/bin/sh
    
      pingResponse="$(redis-cli -h localhost ping | head -n1 | awk '{print $1;}')"
      if [ "$?" -eq "124" ]; then
        echo "PING timed out"
        exit 1
      fi
    
      if [ "$pingResponse" != "PONG"] && [ "$pingResponse" != "LOADING" ] && [ "$pingResponse" != "MASTERDOWN" ]; then
        echo "$pingResponse"
        exit 1
      fi

    readiness.shliveness.sh 指令碼會使用 redis-cli ping 檢查 Redis 伺服器是否正在執行。如果傳回 PONG,表示 Redis 伺服器已啟動並執行。這些指令碼會用於 redis-cluster.yaml

    如要進一步瞭解這個 ConfigMap 中的 Redis 參數,請參閱 Redis Cluster 教學課程中的「Redis Cluster 設定參數」一節。

  2. 部署 ConfigMap:

    kubectl apply -f redis-configmap.yaml
    
  3. 請參閱下方的 StatefulSet (redis-cluster.yaml) 程式碼片段,瞭解 Readiness 探測器和 Liveness 探測器的用法。

    如要瞭解如何在 Kubernetes 中設定探測功能,請參閱「設定探測功能」。

    startupProbe:
      periodSeconds: 5
      timeoutSeconds: 5
      successThreshold: 1
      failureThreshold: 20
      tcpSocket:
        port: redis
    livenessProbe:
      periodSeconds: 5
      timeoutSeconds: 5
      successThreshold: 1
      failureThreshold: 5
      exec:
        command: ["sh", "-c", "/probes/liveness.sh"]
    readinessProbe:
      periodSeconds: 5
      timeoutSeconds: 1
      successThreshold: 1
      failureThreshold: 5
      exec:
        command: ["sh", "-c", "/probes/readiness.sh"]

    強烈建議您在升級節點集區時使用就緒和存活探查,確保 Pod 在升級期間處於就緒狀態。

  4. 部署 StatefulSet:

    kubectl apply -f redis-cluster.yaml
    
  5. 名為 redis-service.yaml 的無標頭 Service 用於 Redis 節點的連線。「clusterIP」欄位設為「None」,以便建立無標題服務。

    部署服務:

    kubectl apply -f redis-service.yaml
    
  6. 等待約兩分鐘,然後使用下列指令確認所有 Pod 都在執行中:

    kubectl get pods
    

    您會看到類似以下範例的輸出內容:

    NAME      READY   STATUS              RESTARTS   AGE
    redis-0   1/1     Running             0          2m29s
    redis-1   1/1     Running             0          2m8s
    redis-2   1/1     Running             0          107s
    redis-3   1/1     Running             0          85s
    redis-4   1/1     Running             0          54s
    redis-5   1/1     Running             0          23s
    
  7. 執行下列指令,確認永久磁碟區已建立:

    kubectl get pv
    

    您會看到類似以下範例的輸出內容:

    NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   REASON   AGE
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-5   standard                75s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-1   standard                2m59s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-3   standard                2m16s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-2   standard                2m38s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-0   standard                3m20s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-4   standard                104s
    

    在這個輸出內容中,HASH 代表附加至每個永久磁碟區名稱的雜湊。

將角色指派給 Redis 叢集

設定完成後,請將角色指派給 Redis 叢集。

下列指令碼會取得 Pod IP 位址,然後將每個 Pod IP 位址傳遞至指令,指派領導者和追隨者角色:

#!/bin/bash
# Usage: ./roles.sh

urls=$(kubectl get pods -l app=redis -o jsonpath='{range.items[*]}{.status.podIP} ')
command="kubectl exec -it redis-0 -- redis-cli --cluster create --cluster-replicas 1 "

for url in $urls
do
    command+=$url":6379 "
done

echo "Executing command: " $command
$command

如要將角色指派給 Redis 叢集,請完成下列步驟:

  1. 執行指令碼:

    chmod +x ./roles.sh
    ./roles.sh
    
  2. 在系統提示時輸入 yes

  3. 登入 Redis 節點,檢查節點的角色。舉例來說,如要確認 redis-0 具有領導者角色,請執行下列指令:

    kubectl exec -it redis-0 -- redis-cli role
    

    您會看到類似以下範例的輸出內容:

    1) "master"
    2) (integer) 574
    3) 1) 1) "10.28.2.3"
           2) "6379"
           3) "574"
    

部署 Redis 用戶端應用程式

如要將應用程式部署至您建立的 GKE 叢集,請為應用程式定義 Deployment。名為 app-deployment.yaml 的檔案包含應用程式的部署定義。

如要進一步瞭解這項 Deployment 中使用的探針和 Pod 親和性規則,請參閱「GKE 最佳做法:設計及建構高可用性叢集」。

如要建立 Deployment,請完成下列步驟:

  1. 套用部署作業:

    kubectl apply -f app-deployment.yaml
    
  2. 透過負載平衡器公開應用程式:

    kubectl expose deployment hello-web \
        --type=LoadBalancer \
        --port 80 \
        --target-port 8080
    
  3. 等待約一分鐘,然後執行下列指令,擷取應用程式的外部 IP 位址:

    kubectl get service
    

    從輸出內容中,複製 hello-web's EXTERNAL-IP 欄列出的值:

    NAME             TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)              AGE
    hello-web        LoadBalancer   10.13.10.55   EXTERNAL_IP   80:30703/TCP         166m
    
  4. EXTERNAL_IP 貼到網路瀏覽器中,確認應用程式是否正常運作。您會看到類似以下範例的輸出內容:

    I have been hit [1] times since deployment!
    

    記下造訪次數。您需要在「測試應用程式中斷情形」一節中使用。

  5. 為您剛複製的 EXTERNAL_IP 設定變數。您會在下一節建立指令碼來測試應用程式時,使用這個值:

    export IP=EXTERNAL_IP
    

設定節點集區升級的最佳做法

請對有狀態應用程式執行這些最佳做法,在節點集區升級期間盡量提升可用性。

設定 Pod disruption budget (PDB)

建立 Pod 中斷預算,限制自願中斷期間同時停止的備用 Pod 數量。這項功能適用於有狀態應用程式,因為升級期間需要一定數量的備用資源才能使用。

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: redis-pdb
spec:
  minAvailable: 3
  selector:
    matchLabels:
      app: redis

在 PDB 定義中:

  • app 指定這個 PDB 適用的應用程式。
  • minAvailable 會設定中斷期間可用的 Pod 數量下限。可以是值或百分比 (例如 30%)。
  • maxUnavailable 會設定中斷期間可停用的 Pod 數量上限。也可以是值或百分比。

如要設定 PDB,請完成下列步驟:

  1. 部署 PDB:

    kubectl apply -f pdb-minavailable.yaml
    
  2. 確認 PDB 是否已建立:

    kubectl get pdb
    

設定維護期間和排除時段

系統代您升級控制層時,節點自動升級功能可簡化升級程序,並更新叢集中的節點。這項功能預設為啟用。 詳情請參閱自動升級節點

使用維護期間和維護排除時段設定時間範圍,控管 GKE 叢集可進行維護作業的時間:

  1. 設定維護期間,從 2022 年 8 月 19 日凌晨 2 點 (世界標準時間) 開始,並在四小時後結束。這項維護作業每天都會執行,在這段時間內,系統可以自動執行維護作業。

    gcloud container clusters update redis-test \
       --maintenance-window-start 2022-08-19T02:00:00Z \
       --maintenance-window-end 2022-08-19T06:00:00Z \
       --maintenance-window-recurrence FREQ=DAILY
    
  2. 設定排除時段,避免在新年假期進行維護作業。這個維護作業排除時段使用 no_upgrades 範圍。在這段期間內,系統不得自動執行任何維護作業。詳情請參閱「排除的維護範圍」。

    gcloud container clusters update redis-test \
       --add-maintenance-exclusion-name new-year \
       --add-maintenance-exclusion-start 2022-12-26T00:00:00Z \
       --add-maintenance-exclusion-end 2023-01-02T02:00:00Z \
       --add-maintenance-exclusion-scope no_upgrades
    
  3. 確認維護期間和排除時段已套用。查看 maintenancePolicy: 下方

    gcloud container clusters describe redis-test
    

詳情請參閱「設定維護期間和排除時段」。

設定節點升級策略

您可以為 GKE 叢集中的節點集區使用兩種節點升級策略:藍綠升級節點數擴充升級。詳情請參閱「節點升級策略」。

藍綠升級

如果工作負載較無法容忍服務中斷,且可接受因資源用量增加而導致的暫時性費用上漲,請選擇藍綠升級。

執行下列指令,將目前的節點集區變更為藍綠升級策略。

gcloud container node-pools update default-pool \
--cluster=redis-test \
--enable-blue-green-upgrade \
--location CONTROL_PLANE_LOCATION \
--node-pool-soak-duration=120s

為節省節點集區過渡期時間,本教學課程將節點集區過渡期設為兩分鐘。這個階段用於驗證藍色集區節點清空後的工作負載健康狀態。建議將節點集浸泡時間設為一小時 (3600 秒),或最適合應用程式的時間長度。

如要進一步瞭解如何管理 Pod 分配,請參閱「將 Pod 部署至特定節點集區」和「將服務部署至特定節點集區」。

如要進一步瞭解如何設定藍綠升級,請參閱「設定藍綠升級」。

節點數擴充升級

如果成本效益很重要,且工作負載可在 60 分鐘內容許正常關機 (GKE 最多會尊重 PDB 60 分鐘),請選擇突波升級。

執行下列指令,將目前的節點集區變更為突增升級策略。

gcloud container node-pools update default-pool \
--max-surge-upgrade=1 \
--max-unavailable-upgrade=0 \
--cluster=redis-test

使用這項設定 (maxSurge=1maxUnavailable=0) 時,升級期間只能將一個突波節點新增至節點集區,因此一次只能升級一個節點。這項設定可在升級期間加快 Pod 重新啟動速度,同時保守地進行升級。

如要進一步瞭解如何設定突波升級,請參閱「設定突波升級」。

檢查目前的節點集區設定:

   gcloud container node-pools describe default-pool \
   --cluster redis-test \
   --location CONTROL_PLANE_LOCATION

如要進一步瞭解如何查看節點集區,請參閱「查看叢集中的節點集區」。

測試應用程式

在本節中,您會使用兩個指令碼,一個用於將要求傳送至應用程式,另一個則用於評估要求成功率。您可以使用這些指令碼評估叢集升級時發生的情況。

如要建立指令碼,請按照下列步驟操作:

  1. 變更為包含指令碼的目錄:

    cd
    cd kubernetes-engine-samples/quickstarts/hello-app-redis/scripts
    
  2. 請參閱名為 generate_load.sh 的指令碼,該指令碼會將每秒查詢次數 (QPS) 要求傳送至應用程式。指令碼會將 HTTP 回應代碼儲存到目前目錄中,並命名為 output。您會在下一個步驟建立的指令碼中使用 output 值。

    #!/bin/bash
    # Usage: ./generate_load.sh <IP> <QPS>
    
    IP=$1
    QPS=$2
    
    while true
      do for N in $(seq 1 $QPS)
        do curl -I -m 5 -s -w "%{http_code}\n" -o /dev/null http://${IP}/ >> output &
        done
      sleep 1
    done
  3. 請參閱名為 print_error_rate.sh 的指令碼,該指令碼會根據 generate_load.sh 產生的輸出內容計算成功率。

    #!/bin/bash
    # Usage: watch ./print_error_rate.sh
    
    TOTAL=$(cat output | wc -l);
    SUCCESS=$(grep "200" output |  wc -l);
    ERROR1=$(grep "000" output |  wc -l)
    ERROR2=$(grep "503" output |  wc -l)
    ERROR3=$(grep "500" output |  wc -l)
    SUCCESS_RATE=$(($SUCCESS * 100 / TOTAL))
    ERROR_RATE=$(($ERROR1 * 100 / TOTAL))
    ERROR_RATE_2=$(($ERROR2 * 100 / TOTAL))
    ERROR_RATE_3=$(($ERROR3 * 100 / TOTAL))
    echo "Success rate: $SUCCESS/$TOTAL (${SUCCESS_RATE}%)"
    echo "App network Error rate: $ERROR1/$TOTAL (${ERROR_RATE}%)"
    echo "Resource Error rate: $ERROR2/$TOTAL (${ERROR_RATE_2}%)"
    echo "Redis Error rate: $ERROR3/$TOTAL (${ERROR_RATE_3}%)"
  4. 授予自己執行指令碼的權限:

    chmod u+x generate_load.sh print_error_rate.sh
    
  5. 為每秒查詢次數設定變數。這個值會用於 generate_load.sh 指令碼,與您為 EXTERNAL_IP 設定的變數相同。建議您將值設為 40。

    export QPS=40
    
  6. 執行 generate_load.sh 指令碼,開始傳送 QPS:

    ./generate_load.sh $IP $QPS 2>&1
    
  7. generate_load.sh 指令碼保持執行狀態,然後開啟新的終端機。在新終端機中執行 print_error_rate.sh 指令碼,檢查錯誤率:

    cd
    cd kubernetes-engine-samples/quickstarts/hello-app-redis/scripts
    watch ./print_error_rate.sh
    

    QPS 建立完成後,您應該會看到 100% 的成功率和 0% 的錯誤率。

  8. 讓這兩個指令碼保持執行狀態,並開啟第三個終端機,準備進行下一節。

升級叢集

如要升級叢集,請完成下列步驟:

  1. 判斷 redis-test 叢集使用的 GKE 版本:

    V=$(gcloud container clusters describe redis-test | grep "version:" | sed "s/version: //")
    echo $V
    

    您會看到類似以下範例的輸出內容:1.22.9-gke.2000

  2. 擷取可用 Kubernetes 版本清單:

    gcloud container get-server-config
    
  3. 在版本清單中找出 validMasterVersions: 區段,然後尋找您在上一個步驟中擷取的 redis-test 版本。如要避免因選擇與節點不相容的版本而違反 GKE 版本差異政策,請從 redis-test 版本前列出的清單中複製版本。

  4. 將叢集的控制層升級至所選版本,並在系統提示時輸入 y

    gcloud container clusters upgrade redis-test \
        --master \
        --cluster-version VERSION
    

    VERSION 替換為您在上一個步驟中從清單選取的版本。

    控制層升級作業需要幾分鐘才能完成。

  5. 將叢集節點升級至所選版本,並在系統提示時輸入 y

    gcloud container clusters upgrade redis-test \
        --cluster-version=VERSION \
        --node-pool=default-pool
    

    VERSION 替換為您從清單中選取的版本。

測試工作負載中斷

在本節中,您將測試應用程式的狀態,並觀察工作負載中斷情形。

  1. 返回執行 ./print_error_rate.sh 的終端機視窗,觀察升級期間的成功率變化。節點關閉升級時,您應該會發現成功率略為下降,應用程式網路錯誤率則略為上升。

    Success rate 欄位會顯示網站的成功造訪次數。請記下這個值。

  2. 在相關終端機中輸入 CTRL+C,停止執行這兩個指令碼。

  3. 在瀏覽器中輸入應用程式的 IP 位址 (這是您在「部署 Redis 用戶端應用程式」一節中複製的 EXTERNAL_IP),返回應用程式的網站。

  4. 觀察應用程式的造訪次數。顯示的數字應等於:

    ORIGINAL_VISIT_NUMBER + SUCCESSFUL_VISIT_NUMBER

    其中 ORIGINAL_VISIT_NUMBER 是您在「部署 Redis 用戶端應用程式」最後一個步驟中記錄的數字,而 SUCCESSFUL_VISIT_NUMBER 是您在本節第一個步驟中記錄的值。