これがなかなか面倒だったのでメモ。
やりたいこと
- terraformでhttp load balancer、gke container clusterを作成する
- 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で管理するべきかというと…どうなんでしょう。
本記事は元記事の転載です。