GKE に Redis クラスタをデプロイする

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

このチュートリアルでは、ステートフル アプリケーションを作成し、アプリケーションを実行する Google Kubernetes Engine(GKE)クラスタをアップグレードする際のおすすめの方法を説明します。このチュートリアルでは、ステートフル アプリケーションをデプロイする例として Redis を使用していますが、同じコンセプトが GKE にデプロイされた他のタイプのステートフル アプリケーションにも適用できます。

目標

このチュートリアルでは、次の手順について説明します。

  1. リリース チャンネルに登録される GKE クラスタを作成します。
  2. GKE で Redis クラスタを作成します。
  3. Redis クライアント アプリケーションの GKE へのデプロイ
  4. ノードプールのアップグレードに関する次のベスト プラクティスを実施します。
    1. Pod 停止予算(PDB)を設定します。
    2. メンテナンスの時間枠と除外を設定します。
    3. ノードプールのアップグレード戦略を、サージ アップグレードまたは Blue/Green アップグレードに設定します。
  5. アプリケーションをテストします。
  6. クラスタをアップグレードします。
  7. ワークロードの中断をテストします。

次の図は、このチュートリアルのクラスタ アーキテクチャの概要を示しています。

アーキテクチャの図

費用

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

プロジェクトを設定する

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud Console のプロジェクト セレクタのページで、[プロジェクトを作成] をクリックして新しい Google Cloud プロジェクトの作成を開始します。

    プロジェクト セレクタに移動

  3. Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。

  4. GKE API を有効にします。

    API を有効にする

  5. Google Cloud Console のプロジェクト セレクタのページで、[プロジェクトを作成] をクリックして新しい Google Cloud プロジェクトの作成を開始します。

    プロジェクト セレクタに移動

  6. Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。

  7. GKE API を有効にします。

    API を有効にする

Google Cloud CLI のデフォルト値を設定する

  1. Google Cloud コンソールで、Cloud Shell インスタンスを起動します。
    Cloud Shell を開く

  2. このサンプルアプリのソースコードをダウンロードします。

     git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
     cd kubernetes-engine-samples/hello-app-redis/manifests
    
  3. デフォルトの環境変数を設定します。

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

    次の値を置き換えます。

リリース チャンネルに登録される GKE クラスタを作成する

GKE クラスタを作成するには、次の手順を行います。

  1. 3 つのノードを持つクラスタを 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)を参照します。以下のスニペットは、readinessProbe と livenessProbe のスクリプトを示しています。

    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.sh スクリプトと liveness.sh スクリプトでは、redis-cli ping を使用して、redis サーバーが実行されているかどうかを確認します。PONG が返された場合、Redis サーバーは稼働しています。これらのスクリプトは redis-cluster.yaml で使用されます。

    この ConfigMap の Redis パラメータの詳細については、Redis クラスタ チュートリアルで Redis クラスタ構成パラメータのセクションをご覧ください。

  2. ConfigMap をデプロイします。

    kubectl apply -f redis-configmap.yaml
    
  3. readinessProbe と livenessProbe の使用方法を示す 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"]

    ノードプールをアップグレードする場合は、readinessProbe と livenessProbe を使用することを強くおすすめします。これにより、アップグレード中に Pod の準備ができます。

  4. StatefulSet をデプロイします。

    kubectl apply -f redis-cluster.yaml
    
  5. redis-service.yaml という名前のヘッドレス Service は、Redis ノードの接続用です。ヘッドレス Service を作成するために、clusterIP フィールドが None に設定されています。

    サービスをデプロイします。

    kubectl apply -f redis-service.yaml
    
  6. 約 2 分待ってから次のコマンドを使用して、すべての 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 定義が含まれます。

この Deployment で使用される Probe と Pod のアフィニティ ルールの詳細については、GKE のベスト プラクティス: 高可用性クラスタの設計と構築をご覧ください。

Deployment を作成するには、次の手順を行います。

  1. Deployment を適用します。

    kubectl apply -f app-deployment.yaml
    
  2. ロードバランサ経由でアプリケーションを公開します。

    kubectl expose deployment hello-web \
        --type=LoadBalancer \
        --port 80 \
        --target-port 8080
    
  3. 約 1 分待ってから次のコマンドを実行して、アプリケーションの外部 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 停止予算(PDB)を設定する

自発的な中断中に同時に停止する複製ポッドの数を制限するポッド停止予算を作成します。これは、アップグレード中にレプリカの数が使用可能になるようにクォーラムを必要とするステートフル アプリケーションに役立ちます。

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 時(UTC)に始まり、4 時間後に終了するメンテナンスの時間枠を設定します。このメンテナンスの時間枠は毎日実行されます。この期間中は、自動メンテナンスが許可されます。

    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 クラスタ内のノードプールに使用できるノードプールのアップグレード戦略には、Blue/Green アップグレードサージ アップグレードの 2 つがあります。詳細については、ノードプールのアップグレード戦略をご覧ください。

Blue/Green アップグレード

ワークロードの中断に対する耐性が低く、リソース使用量の増加による一時的な費用増加が許容される場合は、Blue/Green アップグレードを選択します。

次のコマンドを実行して、現在のノードプールを Blue/Green アップグレード戦略に変更します。

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

このチュートリアルの目的上、ノードプール ソーク期間は、ノードプールのソークフェーズで時間を節約するために 2 分間に設定しています。このフェーズは、Blue プールノードがドレインされた後、ワークロードの正常性を確認するために使用されます。ノードプール ソーク期間を 1 時間(3,600 秒)またはアプリケーションに最適な期間に設定することをおすすめします。

Pod の割り当ての管理の詳細については、Pod を特定のノードプールにデプロイする特定のノードプールに Service をデプロイするをご覧ください。

Blue/Green アップグレードの構成の詳細については、Blue/Green アップグレードを構成するをご覧ください。

サージ アップグレード

コストの最適化が重要であり、ワークロードが 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)では、アップグレード中にノードプールにサージノードを 1 つだけ追加できます。このため、一度にアップグレードできるノードは 1 つだけです。この設定では、アップグレード中の Pod の再起動が速くなります。

サージ アップグレードの構成の詳細については、サージ アップグレードを構成するをご覧ください。

現在のノードプールの構成を確認します。

   gcloud container node-pools describe default-pool \
   --cluster redis-test \
   --zone COMPUTE-ZONE

ノードプールの表示の詳細については、クラスタ内のノードプールを表示するをご覧ください。

アプリケーションをテストする

このセクションでは、アプリケーションにリクエストを送信するスクリプトと、リクエストの成功率を測定する 2 つのスクリプトを使用します。これらのスクリプトを使用して、クラスタをアップグレードしたときに何が起こるかを測定します。

スクリプトを作成するには:

  1. スクリプトが含まれているディレクトリに移動します。

    cd
    cd kubernetes-engine-samples/hello-app-redis/scripts
    
  2. generate_load.sh という名前のスクリプトを参照します。このスクリプトは、秒間クエリ数(QPS)リクエストをアプリケーションに送信します。このスクリプトは、現在のディレクトリの output という名前のファイルに HTTP レスポンス コードを保存します。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. generate_load.sh によって生成される出力に基づいて成功率を計算する print_error_rate.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. QPS の数を格納する変数を設定します。この値は、EXTERNAL_IP に設定した変数と同様に generate_load.sh スクリプトで使用されます。値に 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/hello-app-redis/scripts
    watch ./print_error_rate.sh
    

    QPS が発生すると 100% の成功率と 0% エラー率が表示されます。

  8. 両方のスクリプトを実行したまま、次のセクション用に 3 つ目のターミナルを開きます。

クラスタをアップグレードする

クラスタをアップグレードするには、次の手順を行います。

  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-cluster バージョンを探します。バージョン スキューを回避するため、redis-cluster バージョンのすぐ上にあるバージョンをコピーします。

  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. Google Cloud コンソールで、[リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

クラスタを削除する

このチュートリアル用に作成したクラスタを削除するには、次のコマンドを実行します。

gcloud container clusters delete redis-test

次のステップ