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

  • 0
    いいね
  • 0
    コメント

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

    やりたいこと

    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
    }
    

    だいぶ面倒でしたが、これで目的は果たされました。
    kubernetesをterraformで管理するべきかというと…どうなんでしょう。

    本記事は元記事の転載です。