Terraform v0.12.6から追加されたfor_eachを試してみる
2019-08-16
tl; dr
- 複数のリソースをまとめて作成する方法として
count
の他にfor_each
が追加された - 参照しているlistの要素に変更があると
count
の場合は意図しない変更が入る可能性がある for_each
を使うことで意図しない変更を避けることができる状態を保てる- listを参照しないようなシンプルに複数リソースを作成するような場合は
count
が便利, それ以外はfor_each
が良さそう
for_each?
v0.12で導入されたdynamic-blocksで使えるfor_eachではなく, v0.12.6で導入された複数のリソース作成に使うことができるfor_eachです。
以前からあるcountに近い機能を提供します。
countとfor_eachの違い
count
では作成するリソースに対して0から始まるインデックスを割り当てて管理します。インデックスを用いてlistから要素を参照し, それをリソース作成に使用することも可能です。
複数のIAMユーザーをcountを使って作成する例です。
locals {
users = [
"user1",
"user2",
"user3"
]
}
resource "aws_iam_user" "users" {
count = length(local.users)
name = local.users[count.index]
}
このコードで terraform apply
すると3つのIAMユーザーが作成されます。
次にこの状態から user1
だけを削除しようとします。
locals {
users = [
//"user1",
"user2",
"user3"
]
}
resource "aws_iam_user" "users" {
count = length(local.users)
name = local.users[count.index]
}
この状態で terraform plan
を確認すると3つのリソースに対して変更が発生すると表示されます。
$ terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
- destroy
Terraform will perform the following actions:
# aws_iam_user.users[0] will be updated in-place
~ resource "aws_iam_user" "users" {
arn = "arn:aws:iam::912174252555:user/user1"
force_destroy = false
id = "user1"
~ name = "user1" -> "user2"
path = "/"
tags = {}
unique_id = "AIDA5IYOSQIF7MST5RXY2"
}
# aws_iam_user.users[1] will be updated in-place
~ resource "aws_iam_user" "users" {
arn = "arn:aws:iam::912174252555:user/user2"
force_destroy = false
id = "user2"
~ name = "user2" -> "user3"
path = "/"
tags = {}
unique_id = "AIDA5IYOSQIF5CH4OUE5E"
}
# aws_iam_user.users[2] will be destroyed
- resource "aws_iam_user" "users" {
- arn = "arn:aws:iam::912174252555:user/user3" -> null
- force_destroy = false -> null
- id = "user3" -> null
- name = "user3" -> null
- path = "/" -> null
- tags = {} -> null
- unique_id = "AIDA5IYOSQIFSQKLGN7WU" -> null
}
Plan: 0 to add, 2 to change, 1 to destroy.
user1だけが削除されるのではなく, user2,user3にも変更が発生しています。
多くの場合, 意図する挙動ではないと思います。
次に for_each
を使って同じようにユーザーを作成してみます。
locals {
users = [
"user1",
"user2",
"user3"
]
}
resource "aws_iam_user" "users" {
for_each = toset(local.users)
name = each.value
}
terraform apply
を実行することでcountのときと同じように3つのIAMユーザーを作成できます。
ここからuser1だけを削除しようとすると, 期待通りにuser1だけを削除することができます。
locals {
users = [
//"user1",
"user2",
"user3"
]
}
resource "aws_iam_user" "users" {
for_each = toset(local.users)
name = each.value
}
$ terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_iam_user.users["user1"] will be destroyed
- resource "aws_iam_user" "users" {
- arn = "arn:aws:iam::912174252555:user/user1" -> null
- force_destroy = false -> null
- id = "user1" -> null
- name = "user1" -> null
- path = "/" -> null
- tags = {} -> null
- unique_id = "AIDA5IYOSQIF3BWKJ7JAX" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.
count
はリソースの管理にインデックスを用いて aws_iam_user.users[0]
のように行われていましたが, for_each
では aws_iam_user.users["user1"]
のように参照するキーを使用するようになったためlistの要素数が変化したり順番が入れ替わったりしても余計な変更を発生させずに済むようになりました。