AWS/Terraform

【Terraform】3AZ分のサブネットを1つの定義で構築してみた

今回はTerraformを用いて、AWS上に3AZ分のサブネットを1つの定義(リソースブロック)で構築しましたので、その方法をご紹介していきます。

1.AWS構成図

Terraformで構築する構成は以下です。
東京リージョンに、1つのVPC、3つのパブリックサブネット(各AZ)の構成です。

Terraformで定義が必要なAWSリソースは、次の5つとなります。
・VPC
・インターネットゲートウェイ
・サブネット
・ルートテーブル
・サブネットとルートテーブルの紐づけ

2.tfファイルの内容

構築に使用するtfファイル(main.tf)の内容は以下です。
※terraform apply1回で構築可

############################################################################
# VPC
############################################################################
resource "aws_vpc" "vpc_01" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "vpc-01"
  }
}

############################################################################
# インターネットゲートウェイ
############################################################################
resource "aws_internet_gateway" "igw_01" {
  vpc_id = aws_vpc.vpc_01.id
  tags = {
    Name = "igw-01"
  }
}

############################################################################
# サブネット
############################################################################
resource "aws_subnet" "public_subnet" {
  for_each = {
    "a" = "10.0.0.0/24"
    "c" = "10.0.1.0/24"
    "d" = "10.0.2.0/24"
  }
  vpc_id            = aws_vpc.vpc_01.id
  cidr_block        = each.value
  availability_zone = "ap-northeast-1${each.key}"
  tags = {
    Name = "public-subnet-${each.key}"
  }
}

############################################################################
# ルートテーブル
############################################################################
resource "aws_route_table" "public_route" {
  vpc_id = aws_vpc.vpc_01.id
  route {
    gateway_id = aws_internet_gateway.igw_01.id
    cidr_block = "0.0.0.0/0"
  }
  tags = {
    Name = "public-route"
  }
}

# サブネットとの紐づけ
resource "aws_route_table_association" "route_public_association" {
  for_each = {
    "a" = "1"
    "c" = "2"
    "d" = "3"
  }
  subnet_id      = aws_subnet.public_subnet["${each.key}"].id
  route_table_id = aws_route_table.public_route.id
}

「for_each」について

サブネット、サブネットとルートテーブルの紐づけで、ループ処理を行う「for_each」を記述しています。
for_each」は、1つのリソースブロック内に、任意の数だけ “key” = “value” を定義することができます。
リソースブロック内で定義された “key” = “value” の数だけループ処理が走るため、”key” = “value” の数だけリソースが構築されます。
keyは each.key 、valueは each.value と記述してパラメータに指定することができます。

上記サブネットの場合、key にa,c,dの文字列、value に3AZ分のCIDRを定義しています。
そして、CIDRのパラメータに each.value でvalue(10.0.0.0/24,10.0.1.0/24,10.0.2.0/24)を指定しています。
AZ・Nameタグのパラメータに each.key でkey(a,c,d)を指定しています。
※Nameタグのように、文字列中に key か value を埋め込みたい場合は ${} で囲います。

サブネットとルートテーブルの紐づけでは、key にa,c,dの文字列、value に1,2,3(valueは使わないので何でもよい)を定義しています。
そして、紐づけ先のサブネットIDに each.key (a,c,d)を指定しています。
※構築時・後はTerraformリソース名の行末に、 [“<for_eachで定義したkey>”] の文字列が付与されて別々のリソースとしてTerraformに認識されます。
例えば、構築したAZ-AのサブネットIDだけをパラメータとして設定したい場合は、 aws_subnet.public_subnet[“a”].id と記述します。
▼terraform planの出力例(リソースブロック名の行末に[“for_eachで定義したkey”]が付与されて別々に構築される)

参考情報

The for_each Meta-Argument(公式ドキュメント)https://www.terraform.io/docs/language/meta-arguments/for_each.html

今回はTerraformで、3AZ分のサブネットを1つのリソースブロックで定義・構築する方法をご紹介しました。
補足ですが、ループ処理に用いた「for_each」の “key” = “value” は、variables.tfに定義しておく使い方もあるようです。
しかし、サブネット構築の場合は、CIDRが使い回せる値ではないので、”key” = “value” を変数に入れても可読性が落ちるだけ(複数の箇所を見ないとリソースのパラメータが分からない)です。
言わずもがなですが、他のエンジニアが見てもすぐに内容が分かるtfファイルの方が、チーム内や部署間での内容・構築の連携がはかどります。

この記事を通して、少しでもTerraform習得のお役に立てれば幸いです。