GKEでkubernetesのnodesをロードバランサーのバックエンドとして使いたいとき with terraform


これがなかなか面倒だったのでメモ。

やりたいこと

  1. terraformでhttp load balancer、gke container clusterを作成する
  2. http load balancerのバックエンドとしてclusterのnodeを登録する

つくりかた

1. http load balancerを作成する

googleのhttp load balancerは疎結合な部品の組み合わせで成り立っており、
http load balancer = global forwarding rule + target http proxy + url map
です。
terraformのdocを参考にまるっと作ります。

2. GKE clusterを作成する

これは特に意識せずにterraformで作成して問題ないですが、一点だけ注意しないといけないのは

 addons_config {
   http_load_balancing {
     disabled = false
   }
   horizontal_pod_autoscaling {
     disabled = true
   }
 }

のように、GKE上でさらにload balancerを作らないようにします。
ここでtrueにしてしまうと、ロードバランサーの下にさらにロードバランサーがぶら下がることになってしまうので。
terraformで作成した時、自動的にnodeとしてインスタンスがいくつか立ち上がります。

3. backend serviceにnodesを登録

ここが一番困ったところ。
なぜなら、google_container_cluster.cluster-sample.instance_group_urlsというreferenceが返してくれるのは
instance groupではなくinstance group managerだからです。
これはgoogleのapiの仕様の問題らしくてhashicorpの対応の外
apiのリファレンスを読んでいたところ、instanceGroupManager を instanceGroupに書き換えれば
instance groupのuriになることがわかったので、terraformのreplaceで”Manager”を削除しました。

resource "google_compute_backend_service" "backend-sample" {
 name        = "backend-sample"
 port_name   = "http"
 protocol    = "HTTP"
 timeout_sec = 5

 backend {
   group = "${replace(element(google_container_cluster.cluster-sample.instance_group_urls, 1), "Manager","")}"
 }
 health_checks = ["${google_compute_http_health_check.hc-sample.self_link}"]
}

4. ロードバランサーのヘルスチェックが通るように、firewallとhealthcheckを作成する

ここも面倒だったところ。
もちろんセキュリティ的にできるだけnodeにアクセスできるportは弾きたいところですが、
ロードバランサーのhttpだけを許可したいときにどうやるのか?
先ほど書いたように、nodeが自動的に作成される前にinstance templateが自動で作成されます。
nodeは一意のrandomなtagを付与されているので、このtagに対してfirewallルールを作成します。
タイミング的にclusterを作った後にしかrandomなtagがわからないので、terraformのnull resourceを使います。
terraformの意味が。。。

resource "null_resource" "cluster-attach-fw" {
 triggers {
   instance-group-url = "${google_container_cluster.cluster-sample.instance_group_urls.0}"
 }

 provisioner "local-exec" {
   command = <<EOT
     CLUSTER_TEMPLATE=$(echo $(gcloud compute instance-templates list | grep cluster-sample | cut -d ' ' -f1))
     TARGET_TAG=$(echo $(gcloud compute instance-templates describe $CLUSTER_TEMPLATE --format json | jq -r .properties.tags.items[0]))
     gcloud compute firewall-rules create fw-allow-http-lb-$TARGET_TAG \
       --source-ranges 130.211.0.0/22 \
       --target-tags $TARGET_TAG --allow tcp:${var.gke-http-port} --network ${var.network-sample}
EOT
 }
}

130.211.0.0/22については参照
${var.gke-http-port}については、load balancer用に好きなportを指定します。(80でも動作は問題ないですが)
このportは、nodes上で動かしているkubernetes内のServiceで用いるNodeportと一致する必要があります。
そのportを使って通信するので、backend serviceのnamed portも同じように設定します。

resource "null_resource" "set-cluster-nodeports" {
 triggers {
   be-svc-fingerprint = "${google_compute_backend_service.backend-sample.fingerprint}"
 }

 provisioner "local-exec" {
   command = <<EOT
     INSTANCE_GROUP=$(echo ${google_container_cluster.cluster-revprox.instance_group_urls.0} | sed -e 's/.*\(gke[a-z0-9\-]*\)$/\1/')
     gcloud compute backend-services update backend-sample --port=${var.gke-http-port}
     gcloud compute instance-groups managed set-named-ports $INSTANCE_GROUP \
       --named-ports=http:${var.gke-http-port} --zone=${var.zone}
EOT
 }
}

最後にヘルスチェックですが、指定したNodeport向けに作成します。

resource "google_compute_http_health_check" "hc-sample" {
  name         = "test"
  request_path = "/health_check"

  port = ${var.gke-http-port}
  timeout_sec        = 1
  check_interval_sec = 1
}

だいぶ面倒でしたが、これで目的は果たされました。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする