パーソル&サーバーワークス

ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

【Terraform】for_eachとcountを使ってVPCとEC2を構築

この記事を共有する

目次

はじめに

皆さんこんにちは!サービスGの榎本です。

本記事では、Terraformの for_each と count を活用してVPCとEC2を構築するハンズオンを紹介します。

for_eachとcountの使い分け

for_each

動的に異なる値やキーを使ってリソースを構築する場合に便利です。例えば、CIDRブロックやタグが異なる複数のVPCを作る場合に使用します。
本記事ではVPCのサブネット作成時に使用します。

count

同じ定義で複数のリソースを作成したい場合に便利です。例えば、リソース数が固定されている場合に適しています。
本記事ではEC2作成時に使用します。

前提

Terraform開発環境が構築済みであること。

目的

・for_eachを使って動的なキーを基にVPCを構築する方法を理解する。
・countを使ったシンプルな複数EC2の構築方法を学ぶ。

for_each手順(VPC構築)

1. for_eachとcountハンズオン用のディレクトリを作成する

# ディレクトリ作成
mkdir -p terraform-handson/for_each-count/

2. 作成したディレクトリに移動する

# ディレクトリ移動
cd terraform-handson/for_each-count/

3. countでVPCを作成するためのmain.tfファイルを作成する

# main.tfファイル作成
touch main.tf

4. 作成したmain.tfファイルに以下内容を記載する

provider "aws" {
  region = "ap-northeast-1" # 東京リージョン
}
# VPCを作成
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = {
    Name = "terraform-handson-vpc"
  }
}
# インターネットゲートウェイを作成
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "terraform-handson-igw"
  }
}
# サブネットの定義
locals {
  subnets = {
    "public-1a"  = { az = "ap-northeast-1a", cidr = "10.0.1.0/24", type = "public" }
    "private-1a" = { az = "ap-northeast-1a", cidr = "10.0.2.0/24", type = "private" }
    "public-1c"  = { az = "ap-northeast-1c", cidr = "10.0.3.0/24", type = "public" }
    "private-1c" = { az = "ap-northeast-1c", cidr = "10.0.4.0/24", type = "private" }
  }
}
# サブネットを作成
resource "aws_subnet" "main" {
  for_each = local.subnets
  vpc_id                  = aws_vpc.main.id
  cidr_block              = each.value.cidr
  availability_zone       = each.value.az
  map_public_ip_on_launch = each.value.type == "public"
  tags = {
    Name = each.key
    Type = each.value.type
  }
}
# パブリックルートテーブル
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "public-route-table"
  }
}
# プライベートルートテーブル
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "private-route-table"
  }
}
# パブリックサブネットとルートテーブルの関連付け
resource "aws_route_table_association" "public" {
  for_each = { for key, value in local.subnets : key => value if value.type == "public" }
  subnet_id      = aws_subnet.main[each.key].id
  route_table_id = aws_route_table.public.id
}
# プライベートサブネットとルートテーブルの関連付け
resource "aws_route_table_association" "private" {
  for_each = { for key, value in local.subnets : key => value if value.type == "private" }
  subnet_id      = aws_subnet.main[each.key].id
  route_table_id = aws_route_table.private.id
}
# インターネットゲートウェイへのルート
resource "aws_route" "internet_access" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}

5. コマンドを順番に実行する

terraform init
terraform plan
terraform apply

6. マネジメントコンソールのVPCコンソールを開き、リソースが作成されていることを確認する

count手順

1. 同ディレクトリのmain.tfファイルに以下内容を追記する
本記事ではプライベートサブネットのみにEC2を構築するコードを記載する。
※以下追記コードと、追記コード反映済みのmain.tfコード全体内容を示す。

▼追記コード

# private サブネットのみに対応するリストを作成
locals {
  private_subnets = [for key, value in local.subnets : key if value.type == "private"]
}
# プライベートサブネットのみにEC2を作成
resource "aws_instance" "private_ec2" {
  count         = length(local.private_subnets) # プライベートサブネット数分インスタンスを作成
  ami           = "ami-023ff3d4ab11b2525"       # AmazonLinux2023 の AMI ID
  instance_type = "t2.micro"
  # 各インスタンスのサブネットを指定
  subnet_id = aws_subnet.main[local.private_subnets[count.index]].id
  # 各インスタンスの名前タグ
  tags = {
    Name = "Instance-${local.private_subnets[count.index]}"
  }
}

▼main.tfコード全体

provider "aws" {
  region = "ap-northeast-1" # 東京リージョン
}
# VPCを作成
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = {
    Name = "terraform-handson-vpc"
  }
}
# インターネットゲートウェイを作成
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "terraform-handson-igw"
  }
}
# サブネットの定義
locals {
  subnets = {
    "public-1a"  = { az = "ap-northeast-1a", cidr = "10.0.1.0/24", type = "public" }
    "private-1a" = { az = "ap-northeast-1a", cidr = "10.0.2.0/24", type = "private" }
    "public-1c"  = { az = "ap-northeast-1c", cidr = "10.0.3.0/24", type = "public" }
    "private-1c" = { az = "ap-northeast-1c", cidr = "10.0.4.0/24", type = "private" }
  }
}
# サブネットを作成
resource "aws_subnet" "main" {
  for_each = local.subnets
  vpc_id                  = aws_vpc.main.id
  cidr_block              = each.value.cidr
  availability_zone       = each.value.az
  map_public_ip_on_launch = each.value.type == "public"
  tags = {
    Name = each.key
    Type = each.value.type
  }
}
# パブリックルートテーブル
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "public-route-table"
  }
}
# プライベートルートテーブル
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  tags = {
    Name = "private-route-table"
  }
}
# パブリックサブネットとルートテーブルの関連付け
resource "aws_route_table_association" "public" {
  for_each = { for key, value in local.subnets : key => value if value.type == "public" }
  subnet_id      = aws_subnet.main[each.key].id
  route_table_id = aws_route_table.public.id
}
# プライベートサブネットとルートテーブルの関連付け
resource "aws_route_table_association" "private" {
  for_each = { for key, value in local.subnets : key => value if value.type == "private" }
  subnet_id      = aws_subnet.main[each.key].id
  route_table_id = aws_route_table.private.id
}
# インターネットゲートウェイへのルート
resource "aws_route" "internet_access" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}
# private サブネットのみに対応するリストを作成
locals {
  private_subnets = [for key, value in local.subnets : key if value.type == "private"]
}
# プライベートサブネットのみにEC2を作成
resource "aws_instance" "private_ec2" {
  count         = length(local.private_subnets) # プライベートサブネット数分インスタンスを作成
  ami           = "ami-023ff3d4ab11b2525"       # AmazonLinux2023 の AMI ID
  instance_type = "t2.micro"
  # 各インスタンスのサブネットを指定
  subnet_id = aws_subnet.main[local.private_subnets[count.index]].id
  # 各インスタンスの名前タグ
  tags = {
    Name = "Instance-${local.private_subnets[count.index]}"
  }
}

2. コマンドを順番に実行する

terraform init
terraform plan
terraform apply

3. マネジメントコンソールのEC2コンソールを開き、リソースが作成されていることを確認する

4. 構築した環境を削除する

terraform destroy

まとめ

for_eachとcountを利用することで、コードの行数を減らすことが可能です!
ただ多用すると可読性低下の可能性があるため注意してください!

この記事は私が書きました

榎本 将希

2024 Japan AWS All Certifications Engineers   サッカー観戦とサウナが好きです!   機械学習を勉強中です!

榎本 将希

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。