在 GKE 上部署 Redis 叢集


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

目標

本教學課程包含下列步驟:

  1. 建立已在發布管道註冊的 GKE 叢集。
  2. 在 GKE 上建立 Redis 叢集
  3. 將 Redis 用戶端應用程式部署至 GKE。
  4. 請遵循下列節點集區升級最佳做法:
    1. 設定 Pod 中斷預算 (PDB)
    2. 設定維護期間和排除時段
    3. 節點升級策略設為大量升級藍綠升級
  5. 測試應用程式。
  6. 升級叢集。
  7. 測試工作負載中斷情形。

下圖顯示本教學課程的叢集架構概略視圖:

架構圖

費用

在本文件中,您會使用 Google Cloud的下列計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用資格。

完成本文所述工作後,您可以刪除已建立的資源,避免繼續計費。詳情請參閱清除所用資源一節。

事前準備

設定專案

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the GKE API.

    Enable the API

  5. In the Google Cloud console, on the project selector page, click Create project to begin creating a new Google Cloud project.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the GKE API.

    Enable the API

  8. 設定 Google Cloud CLI 的預設值

    1. 在 Google Cloud 控制台中啟動 Cloud Shell 執行個體:
      開啟 Cloud Shell

    2. 下載這個範例應用程式的原始碼:

       git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
       cd kubernetes-engine-samples/quickstarts/hello-app-redis/manifests
      
    3. 設定預設環境變數:

       gcloud config set project PROJECT-ID
       gcloud config set compute/zone COMPUTE-ZONE
      

      替換下列值:

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

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

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

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

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

      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) 程式碼片段,瞭解如何使用就緒探測和存活探測。

    如要瞭解如何在 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 \
--zone COMPUTE-ZONE \
--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 \
   --zone COMPUTE-ZONE

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

測試應用程式

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

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

  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 是您在本節第一個步驟中記錄的值。

清除所用資源

完成教學課程後,您可以清除所建立的資源,這樣資源就不會繼續使用配額,也不會產生費用。下列各節將說明如何刪除或關閉這些資源。

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。

如要刪除專案:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

刪除叢集

如要刪除為本教學課程建立的叢集,請執行下列指令:

gcloud container clusters delete redis-test

後續步驟