Terraformの真髄:`for_each`と`dynamic`ブロックでコードの「濁流」を止める極意
Terraformを書いていると、いつの間にか「コピペ地獄」に陥っていないか?
「似たようなセキュリティグループルールを10個書く」「サブネットごとに微妙に異なる設定を追記する」。そんなDRY原則を無視したコードは、いずれ負債となり、君の夜を奪うことになる。
今日は、中級者から「真のプロ」へ脱皮するための、Terraformにおける動的生成の極致を伝授する。
—
1. なぜ`count`ではなく`for_each`なのか?
まず大前提だ。`count`は、配列のインデックスに依存する。もし途中の要素を削除したらどうなる?後ろのインデックスがすべてズレて、既存のリソースが破壊・再作成される。これがインフラエンジニアの悪夢だ。
`for_each`は、MapやSetをキーとしてリソースを管理する。キーさえ一意なら、順序は関係ない。「破壊しないIaC」の鉄則は、`count`を捨て、`for_each`を愛することから始まる。
—
2. 実務で直面する「複雑なネスト」を攻略する
複雑なJSONやYAMLからリソースを生成する場合、ただ`for_each`を使うだけでは足りない。`flatten`関数を組み合わせ、多次元配列をフラット化するのがプロの定石だ。
実践:複雑なルール設定をDRYに管理する
例えば、環境ごとに異なる複数のポートを開放するセキュリティグループを定義する場合、以下のように記述する。
localsで複雑なネストを「フラット」に定義する
locals {
# 複雑なJSON構造を想定
raw_config = {
web = { ports = [80, 443], cidrs = [“0.0.0.0/0”] }
api = { ports = [8080], cidrs = [“10.0.0.0/16”] }
}
# リソース生成用にフラット化する魔法のコード
rules = flatten([
for service, config in local.raw_config : [
for port in config.ports : {
key = “${service}-${port}”
port = port
cidr = config.cidrs
}
]
])
}
resource “aws_security_group_rule” “ingress” {
for_each = { for rule in local.rules : rule.key => rule }
type = “ingress”
from_port = each.value.port
to_port = each.value.port
protocol = “tcp”
cidr_blocks = each.value.cidr
security_group_id = aws_security_group.main.id
}
この「`flatten` + `for`式」の組み合わせさえあれば、どんな複雑なJSON構造でも恐怖する必要はない。
—
3. `dynamic`ブロックのネスト:可読性の死守
リソースブロックの中にさらにネストされたブロックがある場合、`dynamic`ブロックが必須だが、使いすぎるとコードが読みづらくなる。
コツは、「`dynamic`ブロック内でさらに`dynamic`を使わない」ことだ。 構造が深すぎる場合は、別途リソースとして切り出すのが「疎結合」の原則だ。
許容されるネストの限界例
dynamic “ingress” {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = “tcp”
}
}
—
4. 生産性を極限まで高める「テックリードの道具箱」
ここからは、コードの書き方以上に重要な「環境」の話だ。
推奨プラグイン
- HashiCorp Terraform (VS Code): これがないと始まらない。`terraform validate`を裏で走らせてくれる。
- TFLint: これを入れずにコードをマージするな。クラウドプロバイダー固有の「非推奨設定」や「型エラー」をCIを回す前に教えてくれる。
- Indent-rainbow: 複雑なHCLのインデントを視覚的にサポートする。
設定の共有化ルール(ベストプラクティス)
- `tfvars`の分離: 環境ごとのパラメータは`environments/prod.tfvars`のように必ず分離せよ。
- YAML活用: 複雑な設定はTerraformコードに直書きせず、`config.yaml`を`yamldecode()`で読み込むのが、非エンジニア(PMやセキュリティ担当)との共同編集をスムーズにする唯一の道だ。
開発スピードを加速させるキーボードショートカット (VS Code)
- `Alt + Shift + F`: Terraformコードのフォーマットを強制実行(保存時自動実行設定が必須)。
- `Ctrl + Shift + P` -> `Terraform: Init` / `Plan`: コマンドを打つ時間を節約する。
—
5. 最後に:コードは「読み手」のために書く
どんなに洗練された`for_each`も、他のメンバーが理解できなければ「技術的負債」だ。
複雑なループを書いたときは、必ず`locals`ブロックで意味のある名前を付け、意図をコメントに残すこと。
「動くコード」を作るのは新米でもできる。
「壊れにくく、かつ誰が読んでも意図がわかるコード」を作るのが、我々SREの仕事だ。
明日の朝、君のプロジェクトの`main.tf`が、この知見で少しでもクリーンになっていることを願っている。健闘を祈る。