はじめに
この記事では三ヶ月ほどTerraformに触れてきた人間から見た、Terraformにおける繰り返し処理の使い分けについて記述していく。
Terraformにおける繰り返し処理
Terraformにはcount, for_each, for の三つの繰り返し処理構文が存在する。
それぞれの繰り返し処理についてこれから解説していこうと思う。
count
countは他の中でも直感的でシンプルな繰り返しと言えるのではないかと思う。
同じリソースを単純に複数作成したいときや、数値でのスケーリングが適している場合に向いている。
以下の例ではawsのサーバー用のインスタンスを三つ作成するものである。
resource "aws_instance" "server" {
count = 3
ami = "ami-123456"
instance_type = "t2.micro"
tags = {
Name = "server-${count.index}"
}
}
for_each
for_eachはmapを使用して繰り返しを行う。
リソースごとに異なる設定が必要な場合や、安全な追加・削除が重要な場合に向いている。
以下の例では異なる用途ごとに異なるインスタンスタイプのインスタンスを三つ作成するものである。
resource "aws_instance" "server" {
for_each = {
"web" = "t2.micro"
"api" = "t2.small"
"db" = "t2.medium"
}
ami = "ami-123456"
instance_type = each.value
tags = {
Name = "server-${each.key}"
}
}
for
forは主に変数の加工に使用される。
多くのプログラミング言語に触れていると「繰り返し=for文(やwhile文)」と思われるかもしれないが(少なくとも自分はそう思っていた) Terraformにおいてはforは制御構造を持っていない。主にデータ操作のために設計されたものである。
そのためリソースの作成にはcount, for_eachを使い、その前段階としてforを使って値を生成するというのがTerraformにおける繰り返しの書き方となる。
# forの適切な使用例
locals {
environments = ["Development", "Staging", "Production"]
tags = {
for env in local.environments :
env => {
Environment = env
}
}
}
resource "aws_instance" "servers" {
for_each = local.tags
ami = "ami-123456"
instance_type = "t2.micro"
tags = each.value
}
# このような書き方は文法エラーとなる
resource "aws_instance" "server" {
for env in local.environments {
ami = "ami-123456"
instance_type = "t2.micro"
tags = {
Environment = env
}
}
}
for_eachとcountの削除時の動作について
主にリソースを作成するfor_eachとcountの使い分けについて考えていく。
実際に仕事でTerraformを使用しているときにcountを使っている場所を自分はほぼ見かけない、その一番の理由は削除の安全性にあるのではないかと思う。
実際に三つのインスタンスを生成する例における削除時の動作について見てみる。
- countの場合
locals{
service = [
"web",
"api",
"db"
]
}
resource "aws_instance" "server" {
count = length(local.services)
ami = "ami-123456"
tags = {
Name = "server-${local.services[count.index]}"
}
}
この状態からapiのインスタンスが不要になったとする。
この時、local変数からapiを削除すると残りのリソースの再作成が発生する。なぜならばindexの振り直しが発生するからだ。
上記リソースは作成時には下記のようなリソース名で作成されている。
# web
aws_instance[0]
# api
aws_instance[1]
# db
aws_instance[2]
ここからapiを削除する場合、dbのインスタンスのindexは振り直しになってしまいリソース名が変わってしまう。リソース名が変わるとTerraformでは完全に別物となってしまうのでリソースの再作成が発生してしまい実際のサービスでは瞬断等が発生する原因となる。
- for_eachの場合
resource "aws_instance" "server" {
for_each = {
"web" = "t2.micro"
"api" = "t2.small"
"db" = "t2.medium"
}
ami = "ami-123456"
instance_type = each.value
tags = {
Name = "server-${each.key}"
}
}
この状態からapi用のインスタンスを削除する。
for_eachではキーで識別され、apiのリソースのみが削除され他のリソースは影響を受けることがない。
以上からリソースの追加・削除が行われる業務上でのTerraformではfor_eachがよく使われているのだと考えている。
まとめ
繰り返しはコードの重複を削減したり変更管理の効率化をする上で便利である。
一方で変更による影響範囲の制御等デメリットも存在する。
適切に使い分けながらいいコードを書けるよう私も精進していきたい。