概要 #
前々回は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コード #
- Advanced-Examples/13-gke-bastion-redis-cluster
- 前々回: GKEプライベートクラスタ+踏み台
- 前回: Memorystore for Redis(PSA接続)
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からの実際の読み書きまで確認できる
参考資料 #
- Google Cloud: Memorystore for Redis Cluster Networking
- Google Cloud: Cluster and node specification
- Google Cloud: Service connection policies for Memorystore
- Terraform Registry: google_redis_cluster
- Terraform Registry: google_network_connectivity_service_connection_policy