terraformを使っていたら誰もが意図しない差分と格闘したことがあるはず。
その中でも特に何度applyしても差分が消えず残り続けるものがある。このようなdiffのことを permadiff
と呼ぶ。
permadiffについての解説はMagic ModulesというGoogle Cloud向けproviderのコード生成器におけるドキュメントで取り上げられている。このためどちらかというとGoogle系のエコシステムの中で用いられる用語かもしれない。 実際、terraform-provider-google ではpermadiffの単語は数多く登場するが、terraform-provider-awsではたまに用いられる程度である。
とはいえ、AWS向けかGoogle Cloud向けかに限らず、よく知られる概念でありterraformを使っていると多くの人が遭遇すると思われる。なのでこういったパターンをきちんと定義することは非常に有効に感じた。
具体例
terraform-provider-google v5.44.2のリリースノートにpermadiffという単語が記載されており初めて知った。
google_container_node_pool
の node_config.0.kubelet_config
の算出ロジックに不具合があり、kubelet_configの値を未指定にするとエラーになるというもの。
具体的には以下のコードをapplyした上で node_config.0.kubelet_config を削除するとapply エラーになる。
terraform { required_providers { google = { source = "hashicorp/google" version = "5.44.1" } } } resource "google_service_account" "default" { account_id = "service-account-id" display_name = "Service Account" } resource "google_container_cluster" "primary" { name = "my-gke-cluster" location = "asia-northeast1" remove_default_node_pool = true initial_node_count = 1 } resource "google_container_node_pool" "primary_preemptible_nodes" { name = "my-node-pool" location = "asia-northeast1" cluster = google_container_cluster.primary.name node_count = 1 node_config { preemptible = true machine_type = "e2-medium" service_account = google_service_account.default.email oauth_scopes = [ "https://www.googleapis.com/auth/cloud-platform" ] kubelet_config { cpu_manager_policy = "static" insecure_kubelet_readonly_port_enabled = "TRUE" } } }
plan実行時にdiffが出て、applyは正常終了するけどdiffは解消しない、というケースを想定していたので このようにapplyエラーになるケースでもエラーの原因によってはpermadiffと呼ぶんだなという学びがあった。
もっとわかりやすい例は Cloud Runの metadata.annotations にlaunch-stageを指定する例。
Cloud Runにて preview featureを利用したい場合は metadata.annotations
に "run.googleapis.com/launch-stage": "BETA"
の値を指定する必要がある。
run.googleapis.com/launch-stage sets the launch stage when a preview feature is used.
Cloud Run のトラブルシューティング | Cloud Run Documentation | Google Cloud
resource "google_cloud_run_service" "default" { name = "cloudrun-srv" location = "asia-northeast1" template { spec { containers { image = "gcr.io/cloudrun/hello" } } } metadata { annotations = { "run.googleapis.com/launch-stage" = "BETA" } } }
ただし、preview featureを利用していない場合はmetadata.annotations に "run.googleapis.com/launch-stage": "BETA"
を指定してもGoogle Cloud側で自動的に除去されてしまう。このため、次にplanを実行するときにはまた差分として出力されてしまう。
(この挙動は GitHubのコメント にある程度で、公式な資料としては見付けられなかった
# google_cloud_run_service.default will be updated in-place ~ resource "google_cloud_run_service" "default" { id = "xxxxx" name = "cloudrun-srv" # (4 unchanged attributes hidden) ~ metadata { ~ annotations = { ~ "run.googleapis.com/launch-stage" = null -> "BETA" } ~ effective_annotations = { + "run.googleapis.com/launch-stage" = "BETA" # (6 unchanged elements hidden) } # (8 unchanged attributes hidden) } # (2 unchanged blocks hidden) } Plan: 0 to add, 1 to change, 0 to destroy.
preview featureを利用するときのみ metadata.annotations に "run.googleapis.com/launch-stage": "BETA"
を指定し、利用しない場合は指定を解除する必要がある。