0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS/Terraform】for_eachを使ったコードの書き方

Posted at

はじめに

terraformでAWSインフラを構築しようとしたとき,いろいろ調べるとfor_eachを使うとコードの量の少なくて済むことに行きつくかと思います.  
ただ,私が業務でfor_eachを使用していると実際に使うには勘所を抑える必要があると思ったので,まとめてみました.
これからterraformを使うエンジニアの方の助けになれば嬉しいです.

for_eachの記法

for_eachは要はループ処理です.私の個人的な解釈ですが,for_eachはプログラミング言語(Python)でいうwhile len(num)に近いものだと思います.入力の中身の最後まで繰り返し処理するイメージです(伝われ).
VPCの作成を例とすると下記のように書けます.

set(string)を入力とした場合

locals{
  param = toset(["vpc-a", "vpc-b"])
}
resource "aws_vpc" "vpc" {
  for_each = local.param
  
  cidr_block = "10.0.0.0/16"
  tags = {
    name = each.value
  }
}

ここで入力がset(string)の時限定で,name = each.valuename = each.keyとも書けます.set(string)は要は配列なのでkey=valueの概念がないためどちらでもよいのです.大体の場合はvalueに設定値を書くので,コード全体で統一するためにeach.valueを書くことが多いです.
上記を実行すると以下の2つのVPCが作成されます.

  • CIDR10.0.0.0/16vpc-a
  • CIDR10.0.0.0/16vpc-b

つまり,同じset(string)を入力としたfor_eachは同じパラメータのリソースを複数作成する場合に適しているといえます.

Tips
同じ設定値のリソースを複数作成したい場合等は,set(string)を入力としてfor_eachに渡すと作りやすい

しかし実際は2つのVPCに同じCIDRを使うのではなく,別のCIDRかつ名前も変えたいというシーンが多いのではないかと思います.
そんな時に使えるのがmap型を使用した作り方です.

mapを入力とした場合①

locals{
  param = tomap({
    vpc-a = {
      # vpc-aのパラメータをkey=value形式で書く 
      cidr = "10.0.0.0/16"
    },
    vpc-b = {
      # vpc-bのパラメータをkey=value形式で書く 
      cidr = "10.1.0.0/16"
    }
  })
}
resource "aws_vpc" "vpc" {
  for_each = local.param
  
  cidr_block = each.value.cidr
  tags = {
    name = each.key
  }
}

上記を実行すると以下の2つのVPCが作成されます.

  • CIDR10.0.0.0/16vpc-a
  • CIDR10.1.0.0/16vpc-b

このようにmapを入力に使用することで個々に設定値が異なるリソースを複数作成することができます.
肝心のリソースセクションはコードの中に一つのためコード全体が短くなりやすくなり,個々のリソースの設定値はlocal or variableの中に集約できるため保守性も高くなります.

Tips
異なる設定値のリソースを複数作成したい場合等は,mapを入力としてfor_eachに渡すと作りやすい

コードの中ではeach.valueで統一した方がいいと言っているのにeach.keyを使用しているじゃないか!!
という 几帳面 完璧主義の方向けに以下の書き方を紹介します.

mapを入力とした場合②

locals{
  param = [
    {
      name = "vpc-a"
      cidr = "10.0.0.0/16"
    },
    {
      name = "vpc-b"
      cidr = "10.1.0.0/16"
    }
  ]
}
resource "aws_vpc" "vpc" {
  for_each = {for i in local.param : i.name => i}
  
  cidr_block = each.value.cidr
  tags = {
    name = each.value.name
  }
}

作成されるリソースは"mapを入力とした場合①"の時と同じですが
for_each = {for i in local.param : i.name => i}
ここが難読だと思います.
ここで何が起きているのかというと,for_eachが読み込める形式のobjectに変換しているのです.
今までのfor_each = local.paramでは,すでにfor_eachが読み込める形式であったため変換は必要ありませんでした.
今回のlocal.paramをよく見るとkeyがないんです.だから変換してあげる必要があります.

  1. :の前for i in local.param
    local.paramの値を変数iに格納します
  2. :の後i.name => i
    i.nameをkey, iをvalueとして変換
    その結果以下のようなobjectが内部的に出来上がります.
{
  "vpc-a" = {
      name = "vpc-a"
      cidr = "10.0.0.0/16"
  },
  "vpc-b" = {
      name = "vpc-b"
      cidr = "10.1.0.0/16"
  }
}

なんかみたことありますね.
そう!mapを入力とした場合①で紹介した書き方と同じです.ここではその変換をしているんですね.
こんな書き方もあるよと覚えておくといつか助かることがあるかもしれません.

Tips
{for i in local.param : i.name => i}for_eachで使える形に変換している!

まとめ

for_eachをうまく使うことでコードサイズの削減,保守性の向上が見込めます.
はじめのうちは慣れない記法でてこずるかもしれませんが,使いこなせるとコードの可読性がグン!と上がるのでぜひ積極的に使うようにしてみてはいかがでしょうか?

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?