Terraform: count から for_each へ書き換える
課題
複数のリソースをリストで定義し、各リソースを count
ループで作成した場合、各リソースがインデックス番号で紐付けられます。インデックス番号が変わると既存のリソースは一旦削除されてしまうため、途中の要素を削除したり挿入することができません。
例)
locals {
repositories = [
"test1",
"test2",
"test3",
]
}
resource "aws_ecr_repository" "ecr" {
count = length(local.repositories)
name = local.repositories[count.index]
}
対策
count
の代わりに for_each
を使うことで、各リソースは文字列により紐付けられます。
resource "aws_ecr_repository" "ecr" {
for_each = { for repo in local.repositories : repo => repo }
name = each.value
}
既存リソースの移行
すでに count
を使ってデプロイしていた場合、リソースのキーがインデックス番号から文字列に変わるため、そのまま apply するとすべて作り直されてしまいます。これを避けるため、紐付けを修正します。
-
リソースの一覧を確認
$ terraform state list
aws_ecr_repository.ecr[0]
aws_ecr_repository.ecr[1]
aws_ecr_repository.ecr[2] -
リソースのキーを変更してデプロイ
$ terraform state mv 'aws_ecr_repository.ecr[0]' 'aws_ecr_repository.ecr["test1"]'
Move "aws_ecr_repository.ecr[0]" to "aws_ecr_repository.ecr[\"test1\"]"
Successfully moved 1 object(s).
$ terraform state mv 'aws_ecr_repository.ecr[1]' 'aws_ecr_repository.ecr["test2"]'
Move "aws_ecr_repository.ecr[1]" to "aws_ecr_repository.ecr[\"test2\"]"
Successfully moved 1 object(s).
$ terraform state mv 'aws_ecr_repository.ecr[2]' 'aws_ecr_repository.ecr["test3"]'
Move "aws_ecr_repository.ecr[2]" to "aws_ecr_repository.ecr[\"test3\"]"
Successfully moved 1 object(s).
for_each
に書き換えた定義で、差分が発生していなければ成功です。
$ terraform plan
(略)
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.