🐯

Terraformで条件分岐とループ処理(count, for_each)

2024/01/04に公開

はじめに

Terraformではリソースに対してcountで条件分岐やfor_eachでループ処理のようなものができる。
ただし、countやfor_eachはメタ要素(Terraformリソースにあたえる要素)なので、if文やfor文のように書くことはできないことに注意!
Terraformリソースに真偽値やループ要素を渡すとよしなにリソースを作ってくれるイメージ

countによる条件分岐

名前からして、ループ処理を行いそうで実際にループも行えるが、for_eachがあるため主に条件分岐に使う

  • countが0のとき、リソースを作らない
  • countが1のとき、リソースを作る
main.tf
variable "region" {
  default = "ap-northeast-1"
}

resource "aws_iam_user" "account" {
  count = var.region == "ap-northeast-1" ? 1 : 0
  name  = "account"
}
プラン結果
  # aws_iam_user.account[0] will be created
  + resource "aws_iam_user" "account" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "account"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

countによるループ処理

resourcemodule内でcountに数値を渡すことで可能
要素のインデックスはcount.indexでアクセスできる

main.tf
resource "aws_iam_user" "accounts-by-count" {
  count = 4
  name  = "account-${count.index}"
}

terraform内でのリソース名はaws_iam_user.accounts-by-count[0]のようになる

プラン結果
  # aws_iam_user.accounts-by-count[0] will be created
  + resource "aws_iam_user" "accounts-by-count" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "account-0"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }
    
...省略...

  # aws_iam_user.accounts-by-count[3] will be created
  + resource "aws_iam_user" "accounts-by-count" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "account-3"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

for_eachによるループ処理

terraformリソースに、ループ要素を渡すイメージ
1重ループしかできない(多重ループは後述)

resourcemodule内でfor_eachmapまたはsetを渡すことで可能
渡した要素のキーはeach.key、値はeach.valueでアクセスできる
setの場合、キーと値は同じものとなる)
listはそのままでは渡せないので、toset()を用いる

main.tf
resource "aws_iam_user" "accounts-by-foreach" {
  for_each = toset(["Todd", "James", "Alice", "Dottie"])
  name     = each.key
}

terraform内でのリソース名はaws_iam_user.test-accounts["Todd"]のようになる

プラン結果
  # aws_iam_user.accounts-by-foreach["Alice"] will be created
  + resource "aws_iam_user" "accounts-by-foreach" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "Alice"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # aws_iam_user.accounts-by-foreach["Dottie"] will be created
  + resource "aws_iam_user" "accounts-by-foreach" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "Dottie"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }
...省略...

リストlistをローカル変数にすることもできます

main.tf
locals {
	list=["Todd", "James", "Alice", "Dottie"]
}

resource "aws_iam_user" "accounts-by-foreach" {
  for_each = toset(local.list)
  name     = each.key
}

for_eachによる多重ループ処理

moduleの中でfor_eachを使い、さらにresourceの中でfor_eachを使う

main.tf
locals {
  list = {
    "group_A" = ["Todd", "James", "Alice"],
    "group_B" = ["Todd", "Dottie"]
  }
}

module "module-for-accounts" {
  for_each  = local.list
  source    = "./module"
  group     = each.key
  name_list = each.value
}
module/iam.tf
variable "group" {
  type = string
}

variable "name_list" {
  type = list(string)
}

resource "aws_iam_user" "accounts-by-module" {
  for_each = toset(var.name_list)
  name     = "${var.group}-${each.key}"
}
プラン結果
...省略...
  # module.module-for-accounts["group_A"].aws_iam_user.accounts-by-module["Todd"] will be created
  + resource "aws_iam_user" "accounts-by-module" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "group_A-Todd"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }
...省略...
  # module.module-for-accounts["group_B"].aws_iam_user.accounts-by-module["Dottie"] will be created
  + resource "aws_iam_user" "accounts-by-module" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "group_B-Dottie"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }
...省略...

参考

https://developer.hashicorp.com/terraform/language/meta-arguments/for_each
https://developer.hashicorp.com/terraform/language/meta-arguments/count
https://zenn.dev/wim/articles/terraform_nest_loop

Discussion