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?

【第3回】AWS ECS Fargate 11回シリーズ|Phase 1-2|NAT Gateway & Route Tableの構築

Last updated at Posted at 2026-01-23

この記事について

記事 タイトル 状態
第0回 全体ガイド ✅ 完了
第1回 構成図編 ✅ 完了
第2回 VPC & Subnet ✅ 完了
第3回 NAT Gateway & Route Table 📍今回
第4回 Security Group ⬜ 未読
第5回 ECR & Docker Image ⬜ 未読
第6回 Public ALB ⬜ 未読
第7回 ECS Front & IAM ⬜ 未読
第8回 ECS API & Internal ALB ⬜ 未読
第9回 RDS MySQL ⬜ 未読
第10回 Secrets Manager & 完成 ⬜ 未読

進捗: 27% (3/11記事) | Phase: 1-2 | 🎯 マイルストーン1達成: Phase 1完了!

📁 完全なコードはGitHubで公開:👉 GitHub: fargate-iac-02


1. はじめに

この記事は、Phase 1の後半として、NAT GatewayとRoute Tableを作成します。

1-1. 前回までの振り返り

第2回(Phase 1-1)で作成したもの:

  • ✅ VPC
  • ✅ Subnet × 6(Public/Private/DB)
  • ✅ Internet Gateway

今回(第3回: Phase 1-2)で作成するもの:

  • NAT Gateway × 2
  • Elastic IP × 2
  • Route Table × 2(Public用、Private用)
  • Route Table Association × 6

1-2. この記事で学べること

  • NAT Gatewayの役割と仕組み
  • Route Tableの設計(Public/Private)
  • 通信経路の理解(IGW経由 vs NAT Gateway経由)
  • Multi-AZ構成のNAT Gateway

1-3. 対象読者

  • 第2回を完了した方
  • Phase 1-1(VPC、Subnet、IGW)を作成済みの方

1-4. 想定環境

  • Terraform: v1.9.x
  • Phase 1-1: 実行済み

2. Phase 1-2で作成するもの

2-1. リソース一覧

リソース 数量 配置場所 日額費用(24h) 月額費用
NAT Gateway 2 Public Subnet × 2 $3.00 $90
Elastic IP 2 NAT Gateway用 無料 無料
Route Table (Public) 1 - 無料 無料
Route Table (Private) 2 AZ × 2 無料 無料
Route Table Association 6 Subnet × 6 無料 無料

合計: 16リソース
コスト: 約$3.00/日(約$90/月) - NAT Gatewayのみ課金

💰 NAT Gatewayコスト詳細:

  • 時間料金: $0.062/時間 × 2 = $0.124/時間
  • 日額: $0.124 × 24h = $2.976 ≈ $3.00/日
  • 月額: $3.00 × 30日 = $90/月

2-2. 構成図での位置づけ

Phase 1-2で追加するのは、配置構成図の以下の部分です:

VPC: 10.0.0.0/16
├─ Internet Gateway ← 第2回で作成済み
├─ Route Table: Public (0.0.0.0/0 → IGW) ← 今回作成
├─ Route Table: Private-A (0.0.0.0/0 → NAT Gateway A) ← 今回作成
├─ Route Table: Private-C (0.0.0.0/0 → NAT Gateway C) ← 今回作成
│
├─ Public Subnet A: 10.0.1.0/24 ← 第2回で作成済み
│   └─ NAT Gateway A ← 今回作成
│       └─ Elastic IP A ← 今回作成
│
├─ Public Subnet C: 10.0.2.0/24 ← 第2回で作成済み
│   └─ NAT Gateway C ← 今回作成
│       └─ Elastic IP C ← 今回作成
│
├─ Private Subnet A: 10.0.10.0/24 ← 第2回で作成済み
├─ Private Subnet C: 10.0.11.0/24 ← 第2回で作成済み
├─ DB Subnet A: 10.0.20.0/24 ← 第2回で作成済み
└─ DB Subnet C: 10.0.21.0/24 ← 第2回で作成済み

3. NAT GatewayとRoute Tableの役割

3-1. NAT Gatewayとは

NAT Gateway (Network Address Translation Gateway) は、Private Subnet内のリソースがインターネットにアクセスするためのゲートウェイです。

特徴:

  • Private Subnet → Internet: OK(アウトバウンド)
  • Internet → Private Subnet: NG(インバウンド)

料理で例えると:

  • NAT Gateway = 厨房の勝手口
  • 仕入れ業者(インターネット)から材料を受け取る
  • お客さん(インターネット)は勝手口から入れない

なぜ必要?

ECS Taskは Private Subnetに配置しますが、以下の通信が必要です:

  • ECRからDockerイメージをpull
  • Secrets ManagerからDB パスワードを取得
  • CloudWatch Logsにログを送信

これらはすべてNAT Gateway経由でインターネットに出る必要があります。

3-2. Route Tableとは

Route Tableは、通信経路を定義するルーティングテーブルです。

Public Subnet用のRoute Table:

送信先 ターゲット 意味
10.0.0.0/16 local VPC内はローカル通信
0.0.0.0/0 igw-xxx それ以外はIGW経由

Private Subnet用のRoute Table:

送信先 ターゲット 意味
10.0.0.0/16 local VPC内はローカル通信
0.0.0.0/0 nat-xxx それ以外はNAT Gateway経由

料理で例えると:

  • Route Table = 配達員への指示書
  • 「店内(VPC内)の配達は直接、外部(Internet)は玄関(IGW)または勝手口(NAT)経由で」

3-3. Multi-AZ構成のNAT Gateway

設計の選択肢:

構成 NAT Gateway数 月額費用 可用性
Single-AZ 1 $45
Multi-AZ 2 $90

今回の選択: Multi-AZ(NAT Gateway × 2)

理由:

  • ✅ 片方のAZが障害でも、もう片方で稼働継続
  • ✅ 本番環境で推奨される構成
  • ⚠️ コストは2倍

学習用の最小構成:

  • NAT Gatewayを1つに削減可能(約$45/月の節約)
  • ただし、Multi-AZの利点は失われる

4. ファイル構成

4-1. Phase 1-2で追加するファイル

terraform/phase1-network/
├── main.tf              ← 第2回で作成済み
├── variables.tf         ← 第2回で作成済み
├── terraform.tfvars     ← 第2回で作成済み
├── vpc.tf               ← 第2回で作成済み
├── subnet.tf            ← 第2回で作成済み
├── igw.tf               ← 第2回で作成済み
├── nat.tf               👉 今回作成
├── route_table.tf       👉 今回作成
└── outputs.tf           ← 第2回で作成済み(更新)

4-2. 追加ファイルの詳細

ファイル名 役割 行数
nat.tf NAT Gateway、EIPの定義 35
route_table.tf Route Table、Route、Associationの定義 90

合計: 2ファイル、約125行


5. ファイル別コード解説

5-1. nat.tf - NAT Gateway × 2

ファイルの役割:

  • Elastic IP × 2を作成
  • NAT Gateway × 2を作成

コード:

# terraform/phase1-network/nat.tf

# ==========================================
# Elastic IP × 2(NAT Gateway用)
# ==========================================
resource "aws_eip" "nat" {
  count  = 2
  domain = "vpc"

  tags = {
    Name = "${var.project_name}-nat-eip-${count.index + 1}"
  }
}

# ==========================================
# NAT Gateway × 2
# ==========================================
resource "aws_nat_gateway" "main" {
  count = 2

  allocation_id = aws_eip.nat[count.index].id
  subnet_id     = aws_subnet.public[count.index].id

  tags = {
    Name = "${var.project_name}-nat-gateway-${count.index + 1}"
  }

  depends_on = [aws_internet_gateway.main]
}

ポイント:

  1. Elastic IP:

    • domain = "vpc": VPC用のEIP
    • NAT Gateway用の固定IPアドレス
  2. NAT Gateway:

    • allocation_id: 紐付けるEIPのID
    • subnet_id: Public Subnetに配置(重要!)
    • depends_on: IGWが先に作成されることを保証

なぜPublic Subnetに配置?

NAT Gatewayは、Private Subnetからの通信をインターネットに転送するため、自身はPublic Subnetに配置する必要があります。

Private Subnet内のECS Task
  ↓
NAT Gateway(Public Subnet内)
  ↓
Internet Gateway
  ↓
インターネット

5-2. route_table.tf - Route Table × 2

ファイルの役割:

  • Public Subnet用のRoute Tableを作成
  • Private Subnet用のRoute Tableを作成(AZ × 2)
  • Subnetとの関連付け

コード:

# terraform/phase1-network/route_table.tf

# ==========================================
# Public Subnet用のRoute Table
# ==========================================
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-public-rt"
  }
}

# Public RouteTable用のルート(0.0.0.0/0 → IGW)
resource "aws_route" "public_internet_gateway" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.main.id
}

# Public Subnetとの関連付け
resource "aws_route_table_association" "public" {
  count = 2

  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

# ==========================================
# Private Subnet用のRoute Table(AZ × 2)
# ==========================================
resource "aws_route_table" "private" {
  count = 2

  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-private-rt-${count.index + 1}"
  }
}

# Private RouteTable用のルート(0.0.0.0/0 → NAT Gateway)
resource "aws_route" "private_nat_gateway" {
  count = 2

  route_table_id         = aws_route_table.private[count.index].id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.main[count.index].id
}

# Private Subnetとの関連付け
resource "aws_route_table_association" "private" {
  count = 2

  subnet_id      = aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private[count.index].id
}

# DB Subnetとの関連付け
resource "aws_route_table_association" "db" {
  count = 2

  subnet_id      = aws_subnet.db[count.index].id
  route_table_id = aws_route_table.private[count.index].id
}

ポイント:

  1. Public Route Table:

    • 1つだけ作成
    • 0.0.0.0/0 → IGW
    • Public Subnet × 2と関連付け
  2. Private Route Table:

    • AZごとに2つ作成
    • 0.0.0.0/0 → NAT Gateway(AZごとに異なる)
    • Private Subnet × 2、DB Subnet × 2と関連付け

なぜPrivate Route Tableが2つ?

Multi-AZ構成では、各AZが独立して動作できるようにするため、Route TableもAZごとに分けます。

AZ-1a:
  Private Subnet A → Private RT A → NAT Gateway A

AZ-1c:
  Private Subnet C → Private RT C → NAT Gateway C

5-3. outputs.tf - 出力の更新

第2回で作成したoutputs.tfに、NAT Gateway IDを追加:

# terraform/phase1-network/outputs.tf

# ... 既存のoutput ...

output "nat_gateway_ids" {
  description = "NAT Gateway IDs"
  value       = aws_nat_gateway.main[*].id
}

output "public_route_table_id" {
  description = "Public Route Table ID"
  value       = aws_route_table.public.id
}

output "private_route_table_ids" {
  description = "Private Route Table IDs"
  value       = aws_route_table.private[*].id
}

6. 実行手順

6-1. ファイル追加

Phase 1-1のディレクトリに、2つのファイルを追加:

cd terraform/phase1-network

# nat.tfを作成
# route_table.tfを作成
# outputs.tfを更新

6-2. terraform plan

実行計画の確認:

terraform plan

実行結果:

Terraform will perform the following actions:

  # aws_eip.nat[0] will be created
  # aws_eip.nat[1] will be created
  # aws_nat_gateway.main[0] will be created
  # aws_nat_gateway.main[1] will be created
  # aws_route_table.public will be created
  # aws_route_table.private[0] will be created
  # aws_route_table.private[1] will be created
  # aws_route.public_internet_gateway will be created
  # aws_route.private_nat_gateway[0] will be created
  # aws_route.private_nat_gateway[1] will be created
  # aws_route_table_association.public[0] will be created
  # aws_route_table_association.public[1] will be created
  # aws_route_table_association.private[0] will be created
  # aws_route_table_association.private[1] will be created
  # aws_route_table_association.db[0] will be created
  # aws_route_table_association.db[1] will be created

Plan: 16 to add, 0 to change, 0 to destroy.

ポイント:

  • Plan: 16 to add: 16個のリソースが追加される
  • 既存のリソース(VPC、Subnet、IGW)は変更なし

6-3. terraform apply

実際にリソースを作成:

terraform apply

確認メッセージ:

Do you want to perform these actions?
  Enter a value: yes  👈 yesと入力

実行結果:

aws_eip.nat[0]: Creating...
aws_eip.nat[1]: Creating...
aws_route_table.public: Creating...
aws_route_table.private[0]: Creating...
aws_route_table.private[1]: Creating...
...
aws_nat_gateway.main[0]: Still creating... [1m0s elapsed]
aws_nat_gateway.main[1]: Still creating... [1m0s elapsed]
...
aws_nat_gateway.main[0]: Creation complete after 2m15s
aws_nat_gateway.main[1]: Creation complete after 2m18s
...

Apply complete! Resources: 16 added, 0 changed, 0 destroyed.

所要時間: 約3-4分(NAT Gatewayの作成に時間がかかる)


7. 動作確認

7-1. AWSコンソールで確認

NAT Gateway:

  1. AWSコンソール → VPC → NAT Gateways
  2. 2つのNAT Gatewayが作成されていることを確認
    • myproject-nat-gateway-1(AZ-1a)
    • myproject-nat-gateway-2(AZ-1c)
  3. State: Available

Elastic IP:

  1. VPC → Elastic IPs
  2. 2つのEIPが作成されていることを確認
  3. 各EIPがNAT Gatewayに関連付けられている

Route Table:

  1. VPC → Route Tables
  2. 3つのRoute Tableが作成されていることを確認
    • myproject-public-rt
    • myproject-private-rt-1
    • myproject-private-rt-2

Public Route Tableの内容:

送信先 ターゲット ステータス
10.0.0.0/16 local active
0.0.0.0/0 igw-xxx active

Private Route Table-1の内容:

送信先 ターゲット ステータス
10.0.0.0/16 local active
0.0.0.0/0 nat-xxx1 active

7-2. Subnet関連付けの確認

Public Route Table:

  • Public Subnet A
  • Public Subnet C

Private Route Table-1:

  • Private Subnet A
  • DB Subnet A

Private Route Table-2:

  • Private Subnet C
  • DB Subnet C

8. トラブルシューティング

8-1. エラー1: EIPの上限超過

エラーメッセージ:

Error: Error allocating EIP: AddressLimitExceeded

原因:

  • AWSアカウントのEIP上限(デフォルト5個)に達している

解決策:

  1. 使っていないEIPを削除
  2. AWS Supportにリクエストして上限緩和

8-2. エラー2: NAT Gatewayの作成に失敗

エラーメッセージ:

Error: creating EC2 NAT Gateway: InvalidSubnet.ID

原因:

  • Subnet IDが正しくない
  • Phase 1-1が完了していない

解決策:

# Phase 1-1の状態を確認
terraform output vpc_id
terraform output public_subnet_ids

# 値が正しく出力されるか確認

8-3. エラー3: Route Tableの関連付けエラー

エラーメッセージ:

Error: Resource.AlreadyAssociated

原因:

  • Subnetが既に別のRoute Tableに関連付けられている

解決策:

AWSコンソールでSubnetの関連付けを確認し、不要な関連付けを削除。


9. コスト最適化(学習用)

9-1. NAT Gatewayを1つに削減

学習用の最小構成:

nat.tfを以下のように変更:

# NAT Gateway × 1に削減
resource "aws_eip" "nat" {
  count  = 1  # 2 → 1に変更
  domain = "vpc"

  tags = {
    Name = "${var.project_name}-nat-eip-${count.index + 1}"
  }
}

resource "aws_nat_gateway" "main" {
  count = 1  # 2 → 1に変更

  allocation_id = aws_eip.nat[count.index].id
  subnet_id     = aws_subnet.public[count.index].id

  tags = {
    Name = "${var.project_name}-nat-gateway-${count.index + 1}"
  }

  depends_on = [aws_internet_gateway.main]
}

route_table.tfも修正:

# Private Route Table × 1に統合
resource "aws_route_table" "private" {
  count = 1  # 2 → 1に変更

  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-private-rt"
  }
}

resource "aws_route" "private_nat_gateway" {
  count = 1  # 2 → 1に変更

  route_table_id         = aws_route_table.private[0].id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.main[0].id
}

# Private Subnetとの関連付け(すべて同じRoute Tableに)
resource "aws_route_table_association" "private" {
  count = 2

  subnet_id      = aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private[0].id  # [count.index] → [0]に変更
}

resource "aws_route_table_association" "db" {
  count = 2

  subnet_id      = aws_subnet.db[count.index].id
  route_table_id = aws_route_table.private[0].id  # [count.index] → [0]に変更
}

節約額: 約$45/月

デメリット:

  • Multi-AZ構成ではなくなる
  • AZ-1aが障害の場合、Private Subnetからインターネットに出られない

10. 🎉 Phase 1完了!

10-1. できたこと

✅ NAT Gateway × 2の作成
✅ Route Tableの作成
✅ ネットワーク基盤の完成
✅ Multi-AZ構成の実現

10-2. Phase 1で作成したリソース(合計)

Phase リソース数 主要リソース
Phase 1-1 9 VPC、Subnet × 6、IGW
Phase 1-2 16 NAT Gateway × 2、Route Table × 2
合計 25 -

10-3. 🎯 マイルストーン1達成!

🎉 ネットワーク基盤が完成しました!

VPC、Subnet、NAT Gateway、Route Tableが
Multi-AZ構成で稼働しています。

11. 次回予告

第4回: Phase 2-1 - Security Group設計

次回は、Phase 2として以下を作成します:

  • Security Group × 5
    • alb-public
    • ecs-front
    • alb-internal
    • ecs-api
    • rds

Security Groupの設計思想と、最小権限の原則について学びます。


12. 参考リンク


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?