Spotahome を使用して Redis を GKE にデプロイする


Redis は、主にキャッシュ用に使用されるオープンソースのインメモリ NoSQL データベースです。組み込みレプリケーション、Lua スクリプト、LRU エビクション、トランザクション、オンディスクの永続性、高可用性などを備えています。

このガイドは、Google Kubernetes Engine(GKE)での Redis クラスタのデプロイに関心のあるプラットフォーム管理者、クラウド アーキテクト、運用担当者を対象としています。

このガイドでは、Spotahome Redis オペレーターを使用して Redis クラスタをデプロイする方法について説明します。

オペレーターは Apache License 2.0 でライセンスされています。

Spotahome には次のようなメリットがあります。

  • Kubernetes ネイティブの Redis クラスタ管理
  • Redis Sentinel によって提供される高可用性
  • シームレスな Prometheus 統合によるデータベースのオブザーバビリティ
  • カスタム Redis 構成の設定のサポート

目標

  • Redis 向けに GKE インフラストラクチャを計画して、デプロイする
  • Spotahome Redis オペレーターをデプロイして構成する
  • オペレーターを使用して Redis を構成して、可用性、セキュリティ、オブザーバビリティ、パフォーマンスを確保する

デプロイ アーキテクチャ

このチュートリアルでは、Spotahome Redis オペレーターを使用して、3 つのレプリカで構成される Redis Sentinel クラスタとともに、高可用性 Redis クラスタをリーダーノードと 2 つのリードレプリカのある GKE にデプロイして構成します。

Redis Sentinel は、オープンソースの Redis 用の高可用性およびモニタリング システムです。リーダーとそれに関連するレプリカなどの Redis インスタンスを継続的にモニタリングします。リーダーノードに障害が発生した場合、Sentinel は自動的にレプリカの 1 つを新しいリーダーに昇格させ、データの読み取りと書き込みに使用可能で動作しているリーダーノードが常に存在するようにします。Redis クラスタ内でリーダー障害やフェイルオーバー イベントなどの重大なイベントが発生した場合、Sentinel はメールやその他の通知メカニズムを通じて管理者や他のシステムに通知できます。

また、複数のアベイラビリティ ゾーンに複数の Kubernetes ノードを分散させ、高可用性のリージョンの Redis 用 GKE クラスタをデプロイします。この設定により、フォールト トレランス、スケーラビリティ、地理的冗長性を確保できます。稼働時間と可用性の SLA を提供しながら、ローリング アップデートとメンテナンスが可能になります。詳細については、リージョン クラスタをご覧ください。

次の図は、Redis クラスタが GKE クラスタ内の複数のノードとゾーンでどのように実行されるかを示しています。

この図では、Redis StatefulSet が 3 つの異なるゾーンの 3 つのノードにデプロイされています。GKE がノードとゾーンに StatefulSet をデプロイする方法を制御するには、Pod のアフィニティトポロジの分散ルールを RedisFailover カスタム リソース仕様に設定します。

1 つのゾーンに障害が発生した場合、GKE は推奨構成を使用して、新しいノードで Pod を再スケジュールします。

次の図は、3 つの異なるゾーンの 3 つのノードにスケジュールされている Sentinel Deployment を示しています。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい 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. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

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

  6. Enable the Compute Engine, IAM, GKE, Backup for GKE, and Resource Manager APIs:

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com cloudresourcemanager.googleapis.com
  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

    gcloud init
  9. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

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

  11. Enable the Compute Engine, IAM, GKE, Backup for GKE, and Resource Manager APIs:

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com cloudresourcemanager.googleapis.com
  12. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/storage.objectViewer, roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin, roles/gkebackup.admin, roles/monitoring.viewer

    gcloud projects add-iam-policy-binding PROJECT_ID --member="USER_IDENTIFIER" --role=ROLE
    • Replace PROJECT_ID with your project ID.
    • Replace USER_IDENTIFIER with the identifier for your user account. For example, user:myemail@example.com.

    • Replace ROLE with each individual role.

環境を設定する

このチュートリアルでは、Cloud Shell を使用して Google Cloud でホストされるリソースを管理します。Cloud Shell には、kubectlgcloud CLIHelmTerraform など、このチュートリアルに必要なソフトウェアがプリインストールされています。

Cloud Shell を使用して環境を設定するには、次の操作を行います。

  1. Google Cloud コンソールCloud Shell 有効化アイコンCloud Shell をアクティブにする」をクリックして、Google Cloud コンソールから Cloud Shell セッションを起動します。Google Cloud コンソールの下部ペインでセッションが起動します。

  2. 環境変数を設定します。

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=redis
    export REGION=us-central1
    

    PROJECT_ID の置き換え: Google Cloud のプロジェクト ID に置き換えます。

  3. GitHub リポジトリのクローンを作成します。

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  4. 作業ディレクトリを変更します。

    cd kubernetes-engine-samples/databases/redis-spotahome
    

クラスタ インフラストラクチャを作成する

このセクションでは、Terraform スクリプトを実行して、限定公開の高可用性リージョン GKE クラスタを作成します。次の手順では、コントロール プレーンへの公開アクセスを許可します。

オペレーターは、Standard または Autopilot クラスタを使用してインストールできます。

Standard

次の図は、3 つの異なるゾーンにデプロイされた限定公開のリージョン GKE Standard クラスタを示しています。

このインフラストラクチャをデプロイするには、Cloud Shell から次のコマンドを実行します。

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

プロンプトが表示されたら、「yes」と入力します。このコマンドが完了し、クラスタが準備完了ステータスになるまでに数分かかることがあります。

Terraform が次のリソースを作成します。

  • Kubernetes ノード用の VPC ネットワークとプライベート サブネット
  • NAT 経由でインターネットにアクセスするためのルーター
  • us-central1 リージョンの限定公開 GKE クラスタ
  • 自動スケーリングが有効な 2 つのノードプール(ゾーンあたり 1~2 ノード、最小ゾーンあたり 1 ノード)
  • ロギングとモニタリングの権限を持つ ServiceAccount
  • Backup for GKE(障害復旧用)
  • Google Cloud Managed Service for Prometheus(クラスタ モニタリング用)

出力は次のようになります。

...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...

Autopilot

次の図は、限定公開のリージョン GKE Autopilot クラスタを示しています。

このインフラストラクチャをデプロイするには、Cloud Shell から次のコマンドを実行します。

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

プロンプトが表示されたら、「yes」と入力します。このコマンドが完了し、クラスタが準備完了ステータスになるまでに数分かかることがあります。

Terraform が次のリソースを作成します。

  • Kubernetes ノードの VPC ネットワークとプライベート サブネット
  • NAT 経由でインターネットにアクセスするためのルーター
  • us-central1 リージョンの限定公開 GKE クラスタ
  • ロギングとモニタリングの権限を持つ ServiceAccount
  • Google Cloud Managed Service for Prometheus(クラスタ モニタリング用)

出力は次のようになります。

...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...

クラスタに接続する

Cloud Shell を使用して、クラスタと通信するように kubectl を構成します。

gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --region ${REGION}

Spotahome オペレーターをクラスタにデプロイする

このセクションでは、Helm チャートを使用して Spotahome オペレーターを Kubernetes クラスタにデプロイしてから、Redis クラスタをデプロイします。

  1. Spotahome Redis オペレーターの Helm チャート リポジトリを追加します。

    helm repo add redis-operator https://spotahome.github.io/redis-operator
    
  2. Spotahome オペレーターと Redis クラスタの Namespace を追加します。

    kubectl create ns redis
    
  3. Helm コマンドライン ツールを使用して Spotahome オペレーターをデプロイします。

    helm install redis-operator redis-operator/redis-operator --version 3.2.9 -n redis
    
  4. Helm を使用して Spotahome オペレーターのデプロイ ステータスを確認します。

    helm ls -n redis
    

    出力は次のようになります。

    NAME             NAMESPACE    REVISION    UPDATED                                STATUS      CHART                   APP VERSION
    redis-operator    redis      1           2023-09-12 13:21:48.179503 +0200 CEST    deployed    redis-operator-3.2.9    1.2.4
    

Redis をデプロイする

Redis クラスタ インスタンスの基本構成には、次のコンポーネントが含まれています。

  • Redis ノードの 3 つのレプリカ: 1 つのリーダーと 2 つのリードレプリカ。
  • クォーラムを形成する Sentinel ノードの 3 つのレプリカ。
  • 1 個の CPU リクエストと 2 個の CPU 上限の CPU リソース割り当て(Redis の場合は 4 GB のメモリ リクエストと上限、Sentinel の場合は 100 m / 500 m の CPU と 500 MB)。
  • toleration、nodeAffinitiestopologySpreadConstraints は各ワークロードに構成され、それぞれのノードプールと異なるアベイラビリティ ゾーンを利用して Kubernetes ノード間で適切に分散されます。

この構成は、本番環境に対応した Redis クラスタの作成に必要な最小限の設定を表しています。

基本的な Redis クラスタを作成する

  1. ユーザー認証情報で Secret を作成します。

    export PASSWORD=$(openssl rand -base64 12)
    kubectl create secret generic my-user -n redis \
        --from-literal=password="$PASSWORD"
    

    オペレーターには認証情報を生成する機能がないため、データベースのパスワードを事前に生成する必要があります。

  2. 基本構成を使用して新しい Redis クラスタを作成します。

    kubectl apply -n redis -f manifests/01-basic-cluster/my-cluster.yaml
    

    このコマンドは、CPU、メモリ リクエスト、上限を指定する Spotahome オペレーターの RedisFailover カスタム リソース、さらに、プロビジョニングされた Pod レプリカを Kubernetes ノードに分散するための taint とアフィニティを作成します。

  3. Kubernetes が必要なワークロードを開始するまで数分待ちます。

    kubectl wait pods -l redisfailovers.databases.spotahome.com/name=my-cluster --for condition=Ready --timeout=300s -n redis
    
  4. Redis ワークロードが作成されたことを確認します。

    kubectl get pod,svc,statefulset,deploy,pdb -n redis
    

    出力は次のようになります。

    NAME                                READY   STATUS  RESTARTS   AGE
    pod/redis-operator-5dc65cb7cc-krlcs   1/1   Running   0         49m
    pod/rfr-my-cluster-0                2/2     Running   0         60s
    pod/rfr-my-cluster-1                2/2     Running   0         60s
    pod/rfr-my-cluster-2                2/2     Running   0         60s
    pod/rfs-my-cluster-8475dfd96c-h5zvw   1/1   Running   0         60s
    pod/rfs-my-cluster-8475dfd96c-rmh6f   1/1   Running   0         60s
    pod/rfs-my-cluster-8475dfd96c-shzxh   1/1   Running   0         60s
    
    NAME                    TYPE        CLUSTER-IP  EXTERNAL-IP   PORT(S)   AGE
    service/redis-my-cluster ClusterIP   10.52.14.87   <none>       6389/TCP    55s
    service/redis-operator   ClusterIP   10.52.13.217   <none>      9710/TCP    49m
    service/rfr-my-cluster   ClusterIP   None           <none>      9121/TCP    61s
    service/rfs-my-cluster   ClusterIP   10.52.15.197   <none>      26379/TCP   61s
    
    NAME                            READY   AGE
    statefulset.apps/rfr-my-cluster   3/3   61s
    
    NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/redis-operator   1/1    1           1           50m
    deployment.apps/rfs-my-cluster   3/3    3           3           62s
    
    NAME                                        MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    poddisruptionbudget.policy/rfr-my-cluster   2               N/A             1                   64s
    poddisruptionbudget.policy/rfs-my-cluster   2               N/A             1                   63s
    

オペレーターが次のリソースを作成します。

  • Redis StatefulSet と Sentinel Deployment
  • Redis の 3 つの Pod レプリカ
  • Sentinel の 3 つの Pod レプリカ
  • 2 つの PodDisruptionBudgets。クラスタの整合性のために 2 つ以上の利用可能なレプリカを確保します。
  • rfr-my-cluster Service。Redis の指標を公開します。
  • Redis クラスタのリーダーノードを対象とする redis-my-cluster Service
  • クライアントが Sentinels を通じてクラスタに接続できる rfs-my-cluster サービス。クライアント ライブラリには Sentinel サポートが必要です。

Redis 認証情報を共有する

Spotahome オペレーターの従来の認証方法を使用して、Redis 認証情報をクライアントと共有できます。

requirepass 設定を使用してデータベースのパスワードを使用する必要があります。このパスワードは、すべてのクライアントで使用されます。追加のユーザーを管理するには、Redis CLI コマンドを使用します。

apiVersion: databases.spotahome.com/v1
kind: RedisFailover
metadata:
  name: my-cluster
spec:
  ...
  auth:
    secretPath: my-user

この方法で Redis 認証情報をクライアントと共有する場合は、次の制限があります。

  • Spotahome では、ユーザー管理用のカスタム リソースは提供されません。認証情報を Secret に保存し、auth 仕様でそれらを参照できます。
  • カスタム リソースを使用して TLS 暗号化で接続を保護する方法はありません。
  • 認証情報のライブ更新はサポートされていません

Redis に接続する

Redis クライアントをデプロイし、Kubernetes Secret に保存されているパスワードを使用して認証を行います。

  1. クライアント Pod を実行して Redis クラスタとやり取りします。

    kubectl apply -n redis -f manifests/02-auth/client-pod.yaml
    

    PASS 環境変数は、Vault から my-user Secret を取得します。

  2. Pod の準備ができるまで待ってから、それに接続します。

    kubectl wait pod redis-client --for=condition=Ready --timeout=300s -n redis
    kubectl exec -it redis-client -n redis -- /bin/bash
    
  3. 接続が機能することを確認します。

    redis-cli -h redis-my-cluster -a $PASS --no-auth-warning SET my-key "testvalue"
    

    出力は次のようになります。

    OK
    
  4. my-key 値を取得します。

    redis-cli -h redis-my-cluster -a $PASS --no-auth-warning GET my-key
    

    出力は次のようになります。

    "testvalue"
    
  5. Pod のシェルを終了します。

    exit
    

Prometheus が Redis クラスタの指標を収集する仕組み

次の図は、Prometheus が指標を収集する仕組みを示しています。

この図では、GKE 限定公開クラスタに次のものが存在します。

  • パス / とポート 9121 の指標を収集する Redis Pod
  • Redis Pod からの指標を処理する Prometheus ベースのコレクタ
  • Cloud Monitoring に指標を送信する PodMonitoring リソース

Google Cloud Managed Service for Prometheus は、Prometheus 形式での指標の収集をサポートしています。Cloud Monitoring は、Redis 指標に対して統合ダッシュボードを使用します。

Spotahome オペレーターは、redis_exporter をサイドカーとして使用し、Prometheus 形式でクラスタ指標を公開します。

  1. labelSelector で指標を収集する PodMonitoring リソースを作成します。

    kubectl apply -n redis -f manifests/03-prometheus-metrics/pod-monitoring.yaml
    
  2. Google Cloud コンソールで、GKE クラスタのダッシュボード ページに移動します。

    GKE クラスタ ダッシュボードに移動する

    ダッシュボードにゼロ以外の指標の取り込み率が表示されます。

  3. Google Cloud コンソールで [ダッシュボード] ページに移動します。

    ダッシュボードに移動する

  4. Redis Prometheus の概要ダッシュボードを開きます。ダッシュボードには、接続数とキーが表示されます。ダッシュボードの自動プロビジョニングには数分かかる場合があります。

  5. クライアント Pod に接続し、変数を準備します。

    kubectl exec -it redis-client -n redis -- /bin/bash
    
  6. redis-cli ツールを使用して新しい鍵を作成します。

    for i in {1..50}; do \
      redis-cli -h redis-my-cluster -a $PASS \
      --no-auth-warning SET mykey-$i "myvalue-$i"; \
    done
    
  7. ページを更新し、コマンド/秒のグラフが更新されて実際のデータベース状態が表示されていることを確認します。

  8. Pod のシェルを終了します。

    exit
    

クリーンアップ

プロジェクトを削除する

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

リソースを個別に削除する

  1. 環境変数を設定します。

    export PROJECT_ID=${PROJECT_ID}
    export KUBERNETES_CLUSTER_PREFIX=redis
    export REGION=us-central1
    
  2. terraform destroy コマンドを実行します。

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform -chdir=terraform/FOLDER destroy -var project_id=${PROJECT_ID} \
      -var region=${REGION} \
      -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
    

    FOLDER は、gke-autopilot または gke-standard に置き換えます。

    プロンプトが表示されたら、「yes」と入力します。

  3. アタッチされていないすべてのディスクを検索します。

    export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
    
  4. ディスクを削除します。

    for i in $disk_list; do
      disk_name=$(echo $i| cut -d'|' -f1)
      disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||')
      echo "Deleting $disk_name"
      gcloud compute disks delete $disk_name --zone $disk_zone --quiet
    done
    

次のステップ