↓メインコンテンツへスキップ
  1. Blogs/

TerraformでGKEプライベートクラスタからMemorystore for Redis Clusterへ接続してみた

3 分
Terraform GoogleCloud GKE Redis
0222-nnn
著者
0222-nnn
猫が好き
目次
Terraform-GoogleCloud - この記事は連載の一部です
パート 25: この記事

概要
#

前々回はGKEプライベートクラスタと踏み台を作成しました。前回は、そこにMemorystore for Redis(BASIC)をPrivate Service Access(PSA)で接続しました。

同じMemorystoreでも、Redis Clusterの接続方式はPrivate Service Connect(PSC)です。専用のSubnetとService Connection Policyが必要になります。接続先も単一のホストではなく、Discovery Endpointです。名前が似ているため、前回のPSA接続の設定をそのまま流用しようとするとハマります。この違いを整理しておく必要があります。

Terraformの基本操作と、前々回のGKEプライベートクラスタ+踏み台構成は前提としています。前回のRedis Instance(PSA接続)記事と読み比べると、PSAとPSCの違いが分かりやすくなります。

複数シャード構成、AUTH・転送時暗号化の有効化、レプリカ構成(HA)は最小構成のため扱いません。

検証すること
#

  • Private Service ConnectでGKE用VPCとRedis Clusterを接続できること
  • Memorystore for Redis Cluster(最小構成)を作成できること
  • PodからDiscovery Endpoint経由で実際に接続し、redis-cli -c(cluster mode)でPING・SET・GETが成功すること(Cluster作成の確認とは別)

前提環境
#

  • Google Cloud CLI、Terraform、Docker
  • Billingが有効な検証用Google Cloud Project
  • GKE、Compute Engine、IAM、Memorystoreを操作できるGoogleアカウント
  • 検証時のバージョン:Terraform 1.14.3、google 7.46.0

今回の構成
#

Redis ClusterはPSAのようにVPC同士をPeeringしません。代わりに、Redis側のサービスをVPC内のエンドポイントとして公開します。そのために専用のSubnet(/29)と、どのSubnetをエンドポイントに使うかを定義するServiceConnectionPolicyが必要です。

flowchart TB
    subgraph GCP["Google Cloud"]
        subgraph Project["Project"]
            subgraph Region["asia-northeast1"]
                subgraph VPC["VPC"]
                    subgraph GkeSubnet["GKE Subnet"]
                        Pod["Pod(redis-test)"]
                    end
                    PscSubnet["PSC Subnet
/29"] end end Policy["ServiceConnectionPolicy
service_class: gcp-memorystore-redis"] RedisCluster["Memorystore for Redis Cluster
discovery_endpoints"] end end PscSubnet -.->|"参照"| Policy Policy -.->|"エンドポイントを払い出す"| RedisCluster Pod -->|"redis-cli -c
PING / SET / GET"| RedisCluster

ServiceConnectionPolicyがPSC Subnetを参照し、そのSubnet上にRedis Cluster用のエンドポイントが作られます。VPC Peeringは発生しません。

接続そのものはPSA版と同じくシンプルですが、redis-cliのオプションが異なります。Redis Clusterはデータをシャードに分散する構成です。通常のredis-cliで接続すると、MOVEDというリダイレクト応答を受け取ることがあります。cluster modeを表す-cを付けると、クライアントがリダイレクトへ自動的に追従する仕組みです。

sequenceDiagram
    participant Pod as Pod(redis-test)
    participant Redis as Memorystore for Redis Cluster

    Pod->>Redis: PING(redis-cli -c)
    Redis-->>Pod: PONG
    Pod->>Redis: SET test-key "hello-from-pod"
    Redis-->>Pod: OK
    Pod->>Redis: GET test-key
    Redis-->>Pod: "hello-from-pod"

使用するTerraformコード
#

Private Service Connect用のSubnetとPolicy
#

resource "google_compute_subnetwork" "redis_psc" {
  name          = "${var.network_name}-redis-psc-subnet"
  ip_cidr_range = var.redis_psc_subnet_cidr
  region        = var.region
  network       = google_compute_network.vpc.id
}

resource "google_network_connectivity_service_connection_policy" "redis_psc" {
  name          = "${var.network_name}-redis-psc-policy"
  location      = var.region
  service_class = "gcp-memorystore-redis"
  network       = google_compute_network.vpc.id

  psc_config {
    subnetworks = [google_compute_subnetwork.redis_psc.id]
  }
}

PSC用Subnetは/29(8アドレス)が推奨最小サイズです。GKE Subnet(10.40.0.0/24)やコントロールプレーンのCIDR(172.16.4.0/28)と重複しない範囲を確保します。service_class = "gcp-memorystore-redis"が、このPolicyをMemorystore for Redis Cluster専用として登録します。

Memorystore for Redis Cluster
#

resource "google_redis_cluster" "cache" {
  name          = "${var.cluster_name}-rediscl"
  region        = var.region
  shard_count   = var.redis_shard_count
  replica_count = var.redis_replica_count
  node_type     = var.redis_node_type

  deletion_protection_enabled = false

  psc_configs {
    network = google_compute_network.vpc.id
  }

  transit_encryption_mode = "TRANSIT_ENCRYPTION_MODE_DISABLED"
  authorization_mode      = "AUTH_MODE_DISABLED"

  zone_distribution_config {
    mode = "MULTI_ZONE"
  }

  depends_on = [
    google_network_connectivity_service_connection_policy.redis_psc,
  ]
}

replica_countはレプリカなしの0にしています。可用性が必要な場合は1以上を指定しますが、その分ノード数が増えて課金対象も増えます。node_typeはRedis Clusterで選択できる最小構成のREDIS_SHARED_CORE_NANOです。transit_encryption_modeとauthorization_modeは検証用途のため無効化しています。

設定と実行
#

cd Advanced-Examples/13-gke-bastion-redis-cluster
cp terraform.tfvars.example terraform.tfvars
project_id = "YOUR_PROJECT_ID"
iap_member = "user:YOUR_ACCOUNT"
terraform init
terraform fmt -check
terraform validate
terraform plan
terraform apply

前々回のVPC・踏み台・GKEに加えてRedis Cluster関連のリソースが作成されます。合わせて31リソースです。Redis Clusterの作成に約7分、GKEクラスタの作成に約10分かかりました(並行して進みます)。

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

Outputs:

bastion_name = "tf-adv-gke-rediscl-vm"
cluster_name = "tf-adv-gke-rediscl"
redis_host = "10.44.0.2"
redis_port = 6379

Podから実際に接続できることを確認する
#

Redis Clusterが作成できたことと、Podから実際に接続できることは別です。テスト用Podをデプロイし、redis-cli -cでPING・SET・GETを実行します。

sed -e "s|__REDIS_HOST__|$(terraform output -raw redis_host)|" \
    -e "s|__REDIS_PORT__|$(terraform output -raw redis_port)|" \
  k8s/redis-test-deployment.yaml > /tmp/redis-test-deployment.yaml
gcloud compute scp /tmp/redis-test-deployment.yaml \
  "$(terraform output -raw bastion_name):/tmp/redis-test-deployment.yaml" \
  --zone="$(terraform output -raw zone)" --tunnel-through-iap \
  --project="$(terraform output -raw project_id)"
# 踏み台の中で実行
gcloud container clusters get-credentials "$(terraform output -raw cluster_name)" \
  --zone="$(terraform output -raw zone)" --project="$(terraform output -raw project_id)"
kubectl apply -f /tmp/redis-test-deployment.yaml
kubectl wait --for=condition=ready pod -l app=redis-test --timeout=120s
kubectl logs -l app=redis-test
Connecting to Redis Cluster at 10.44.0.2:6379 ...
PONG
OK
hello-from-pod
Redis Cluster test completed successfully.

PONG、OK、そして書き込んだhello-from-podがそのまま読み出せました。テスト用マニフェストの中身は前回と似ていますが、redis-cliの呼び出しに-cを付けている点だけが異なります。-cを外して同じ手順を試すと、シャードによってはMOVEDが返りコマンドが失敗します。

後片付け
#

terraform destroy
Destroy complete! Resources: 31 destroyed.

GKE ClusterとRedis Clusterは利用中に料金が発生します。Redis Clusterはシャード×ノードで構成されるため、Instance(前回のBASIC)より単価が高くなりやすい構成です。検証後は必ずdestroyします。

まとめ
#

  • Redis ClusterはPSAではなくPSC。専用SubnetとServiceConnectionPolicyが必要
  • 接続先はhost/portではなくdiscovery_endpoints
  • クライアントはredis-cli -c(cluster mode)が必須。付け忘れるとMOVEDで失敗する
  • Cluster作成の確認とは別に、Podからの実際の読み書きまで確認できる

参考資料
#

次回
#

GKEのPodをInternal HTTP LB(NEG)でポート別に振り分けます。

Terraform-GoogleCloud - この記事は連載の一部です
パート 25: この記事

関連記事

TerraformでGKEプライベートクラスタからMemorystore for Redisへ接続してみた
2 分
Terraform GoogleCloud GKE Redis
TerraformでGKEプライベートクラスタと踏み台VMを作成してみた
3 分
Terraform GoogleCloud GKE IAP
TerraformでGKE Workload IdentityからCloud Storageへアクセスしてみた
2 分
Terraform GoogleCloud GKE WorkloadIdentity
Terraform StateをCloud Storage Remote Backendへ移行してみた
2 分
Terraform GoogleCloud CloudStorage
TerraformからGoogle Cloudへ接続してProject情報を取得してみた
3 分
Terraform GoogleCloud
TerraformでArtifact RegistryのDocker Repositoryを作成してみた
2 分
Terraform GoogleCloud Docker