Terraform には、複数の同種リソースを効率的に作成する方法として count と for_each が存在します。その中で、for_each は特に柔軟で、リソースの識別や管理に優れており、順序に依存しないため、安全性が高いです。
1. for_each とは
for_each は、集合(set)またはマップ(map)を基にリソースをループ生成するための仕組みです。
count がインデックス(0,1,2…)に依存するのに対し、for_each は キー(key) を基準にリソースを識別します。そのため、リストの順番が変わってもリソースの再作成を最小限に抑えられます。
2. 基本的な構文
resource "aws_subnet" "example" {
for_each = toset(var.subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = each.value
}
-
for_each:ループ対象を指定 -
each.key:現在の要素のキー(map の場合) -
each.value:現在の要素の値
3. 使用できるデータ型
| 型 | 例 | 説明 |
|---|---|---|
| set | toset(["10.1.10.0/24", "10.1.20.0/24"]) |
値のみを持つ集合 |
| map | { "subnet-a" = "10.1.10.0/24", "subnet-b" = "10.1.20.0/24" } |
キーと値を持つマップ |
4. each.key と each.value の使い分け
-
set の場合
リソースは値をキーとして識別する:aws_subnet.example["10.1.10.0/24"] aws_subnet.example["10.1.20.0/24"] -
map の場合
キーを名前に利用でき、値は CIDR などに設定可能:aws_subnet.example["subnet-a"] aws_subnet.example["subnet-b"]
5. for_each と count の違い
| 項目 | count | for_each |
|---|---|---|
| 識別方法 | インデックス(0,1,…) | キー(文字列) |
| 順序依存 | あり | なし |
| データ型 | list | map / set |
| 推奨場面 | 固定数のリソース | 可変数、名前付きリソース |
| 注意点 | 順序が変わると再作成される | 安全、順序に左右されない |
6. 実践例
variable "subnets" {
type = map(string)
default = {
subnet-a = "10.1.10.0/24"
subnet-b = "10.1.20.0/24"
}
}
resource "aws_vpc" "main" {
cidr_block = "10.1.0.0/16"
}
resource "aws_subnet" "example" {
for_each = var.subnets
vpc_id = aws_vpc.main.id
cidr_block = each.value
tags = {
Name = each.key
}
}
Terraform は以下のリソースを作成する:
aws_subnet.example["subnet-a"]
aws_subnet.example["subnet-b"]
後で subnet-c を追加しても、既存の subnet-a と subnet-b は再作成されず、新しい subnet-c のみが追加される。
7. まとめ
-
for_eachは、キーに基づくリソース識別により、安全かつ柔軟にリソースを管理できる。 - リソース数が変動する場合や順序による誤削除を避けたい場合には、
countよりfor_eachが適している。 - 適切なデータ型(map または set)を使用することで、Terraform による自動管理がより正確になる。