Terraform で list や count を使ってはいけない
Terraform の繰り返し処理(類似リソースの作成)には、
-
list
ではなくset
-
count
ではなくfor_each
を使いましょう。
list
と count
を使うことの問題点
一言で言うと、「terraform のリソース名に list の index が含まれるため、list の中身の変更が容易ではなくなってしまうこと」です。
具体的に説明します。
下記は、list
(配列) と count
を使い、Google Cloud の API を有効化する例です。
locals {
services = [
"artifactregistry.googleapis.com",
"cloudapis.googleapis.com",
"compute.googleapis.com",
"iam.googleapis.com",
"storage.googleapis.com",
]
}
resource "google_project_service" "default" {
count = length(local.services)
service = local.services[count.index]
project = data.google_project.default.id
}
これを terraform apply
すると、リソース名は
google_project_service.default[0]
google_project_service.default[1]
...
google_project_service.default[4]
のようになります。このケースでは、
storage.googleapis.com
は google_project_service.default[4]
に対応しています。
ここで、例えば iam.googleapis.com
API を無効化すべく、対応する行を削除したとします。
そうすると、list での index が -1 された影響で、
storage.googleapis.com
は google_project_service.default[3]
に変わってしまいます。
リソース名が変わってしまうと、Terraform では完全に別物とされるので、リソースの削除と作成(再作成)が発生します。この例では API の無効化 → 有効化が行われてしまいます。
これは全く望ましい挙動ではありません。
ここでは API の無効化を例として挙げましたが、API の有効化も同様で、 index がズレると意図しないリソースの再作成が行われてしまいます。つまり、list
と count
を使うと、list の中身の変更が容易ではなくなってしまうわけです。
set
と for_each
を使うことで解決
上記の問題は set
と for_each
を使うことで解決できます。
下記は、set
(重複しない配列) と for_each
を使い、上例と同様に Google Cloud の API を有効化する例です。
locals {
services = [
"artifactregistry.googleapis.com",
"cloudapis.googleapis.com",
"compute.googleapis.com",
"iam.googleapis.com",
"storage.googleapis.com",
]
}
resource "google_project_service" "default" {
for_each = toset(local.services) # toset で set に変換
service = each.value # each.key でも可
project = data.google_project.default.id
}
これを terraform apply
すると、リソース名は
google_project_service.default["artifactregistry.googleapis.com"]
google_project_service.default["cloudapis.googleapis.com"]
...
google_project_service.default["storage.googleapis.com"]
のようになります。リソース名から list の index が消え、list の値がそのまま使われるようになりました。
storage.googleapis.com
は google_project_service.default["storage.googleapis.com"]
に対応しています。set
が利用されているので、list の中での順序が変わっても、リソース名に変更はなく、意図しないリソースの再作成が行われずに済むようになりました。
Discussion