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?

【第2回】AWS ECS Fargate 11回シリーズ|Phase 1-1|VPC & Subnetの構築

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 & 完成 ⬜ 未読

進捗: 18% (2/11記事) | Phase: 1-1 | 目標: VPC、Subnet × 6、Internet Gateway作成

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


1. はじめに

この記事は、**第1回(構成図編)**で作成した構成図を元に、実際にTerraformでAWSリソースを構築していくシリーズの第2回です。

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

第0回:

  • シリーズ全体のナビゲーション

第1回:

  • 4種類(5図)の構成図を作成
  • 全体の設計方針を決定

今回(第2回):

  • Phase 1-1を実装
  • VPC、Subnet、Internet Gatewayを作成

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

  • VPCの基本と設計思想
  • Subnetの役割(Public/Private/DB)
  • CIDR設計の考え方
  • Multi-AZ構成の利点
  • Terraformの基本操作(init/plan/apply)

1-3. 対象読者

  • 第1回を読んだ方
  • AWSアカウントを持っている方
  • Terraformをインストール済みの方

1-4. 想定環境

  • Terraform: v1.9.x
  • AWS CLI: v2.x
  • OS: macOS / Linux / Windows(WSL2)

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

2-1. リソース一覧

リソース 数量 配置場所 用途
VPC 1 - ネットワークの基盤
Public Subnet 2 AZ-1a, AZ-1c NAT Gateway、Public ALB用
Private Subnet 2 AZ-1a, AZ-1c ECS Task用
DB Subnet 2 AZ-1a, AZ-1c RDS用
Internet Gateway 1 VPC境界 VPCの出入口

合計: 9リソース

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

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

VPC: 10.0.0.0/16
├─ Internet Gateway
│
├─ Public Subnet A: 10.0.1.0/24 (AZ-1a)
├─ Public Subnet C: 10.0.2.0/24 (AZ-1c)
│
├─ Private Subnet A: 10.0.10.0/24 (AZ-1a)
├─ Private Subnet C: 10.0.11.0/24 (AZ-1c)
│
├─ DB Subnet A: 10.0.20.0/24 (AZ-1a)
└─ DB Subnet C: 10.0.21.0/24 (AZ-1c)

次回(第3回)で追加:

  • NAT Gateway × 2
  • Route Table × 2

3. VPCとSubnetの設計思想

3-1. VPCとは

VPC (Virtual Private Cloud) は、AWS上に作成する仮想ネットワークです。

料理で例えると:

  • VPC = レストランの建物全体
  • Subnet = 厨房、ホール、倉庫などの各部屋
  • Internet Gateway = 正面玄関

3-2. CIDR設計の考え方

CIDR (Classless Inter-Domain Routing) は、IPアドレスの範囲を表す記法です。

今回の設計:

用途 CIDR 利用可能IP数 理由
VPC 10.0.0.0/16 65,536 将来の拡張を考慮
Public Subnet 10.0.1.0/24 256 NAT Gateway、ALB用
Private Subnet 10.0.10.0/24 256 ECS Task用
DB Subnet 10.0.20.0/24 256 RDS用

ポイント:

  • VPCは広めに確保(/16)
  • Subnetは目的別に分離(Public/Private/DB)
  • 将来の追加Subnetを考慮して番号を飛ばす(1, 10, 20)

3-3. Multi-AZ構成

AZ (Availability Zone) は、物理的に独立したデータセンターです。

今回の設計:

  • AZ-1a: ap-northeast-1a(東京リージョンのAZ-A)
  • AZ-1c: ap-northeast-1c(東京リージョンのAZ-C)

メリット:

  • ✅ 片方のAZが障害でも、もう片方で稼働継続
  • ✅ AWSが推奨する高可用性構成
  • ✅ RDS Multi-AZの前提条件

料理で例えると:

  • AZ-1a = 本店
  • AZ-1c = 支店
  • 片方が停電でも、もう片方で営業継続

4. ディレクトリ構成

4-1. プロジェクト全体の構成

my-ecs-project/
├── docker-compose/          # 元のdocker-compose構成
└── terraform/
    └── phase1-network/      👉 今回作成
        ├── main.tf
        ├── variables.tf
        ├── terraform.tfvars
        ├── vpc.tf
        ├── subnet.tf
        ├── igw.tf
        └── outputs.tf

4-2. Phase 1-1のファイル構成

ファイル名 役割 行数
main.tf Provider設定、Terraform設定 20
variables.tf 変数定義 40
terraform.tfvars 変数の実際の値 10
vpc.tf VPC定義 15
subnet.tf Subnet × 6定義 80
igw.tf Internet Gateway定義 10
outputs.tf 他Phaseで使う値を出力 30

合計: 7ファイル、約205行


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

5-1. main.tf - Provider設定

ファイルの役割:

  • Terraformのバージョン指定
  • AWSプロバイダーの設定
  • デフォルトタグの設定

コード:

# terraform/phase1-network/main.tf

terraform {
  required_version = ">= 1.9.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region

  default_tags {
    tags = {
      Project   = var.project_name
      ManagedBy = "Terraform"
      Phase     = "1"
    }
  }
}

ポイント:

  1. required_version: Terraform 1.9.0以上を要求
  2. required_providers: AWS Provider 5.x系を使用
  3. default_tags: すべてのリソースに自動的にタグを付与
    • Project: プロジェクト名
    • ManagedBy: Terraformで管理していることを明示
    • Phase: Phase番号(後で削除時に便利)

料理で例えると:

  • main.tf = レシピの冒頭(使う調理器具の指定)
  • Terraform version = 調理器具のバージョン
  • default_tags = すべての料理に店名のラベルを貼る

5-2. variables.tf - 変数定義

ファイルの役割:

  • 変数の定義(型、説明、デフォルト値)

コード:

# terraform/phase1-network/variables.tf

variable "project_name" {
  description = "プロジェクト名(リソース名のプレフィックス)"
  type        = string
}

variable "region" {
  description = "AWSリージョン"
  type        = string
  default     = "ap-northeast-1"
}

variable "azs" {
  description = "利用するAvailability Zone"
  type        = list(string)
  default     = ["ap-northeast-1a", "ap-northeast-1c"]
}

variable "vpc_cidr" {
  description = "VPCのCIDRブロック"
  type        = string
}

variable "public_subnet_cidrs" {
  description = "Public SubnetのCIDRブロック"
  type        = list(string)
}

variable "private_subnet_cidrs" {
  description = "Private SubnetのCIDRブロック"
  type        = list(string)
}

variable "db_subnet_cidrs" {
  description = "DB SubnetのCIDRブロック"
  type        = list(string)
}

ポイント:

  1. description: 変数の説明(日本語OK)
  2. type: 変数の型(string、list、map等)
  3. default: デフォルト値(オプション)

変数の種類:

  • 共通変数: project_name、region、azs
  • Phase 1固有変数: vpc_cidr、subnet_cidrs

5-3. terraform.tfvars - 変数の値

ファイルの役割:

  • 変数の実際の値を設定

コード:

# terraform/phase1-network/terraform.tfvars

project_name = "myproject"
region       = "ap-northeast-1"
azs          = ["ap-northeast-1a", "ap-northeast-1c"]

vpc_cidr = "10.0.0.0/16"

public_subnet_cidrs  = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnet_cidrs = ["10.0.10.0/24", "10.0.11.0/24"]
db_subnet_cidrs      = ["10.0.20.0/24", "10.0.21.0/24"]

ポイント:

  1. project_name: 好きな名前に変更可能
  2. CIDR設計: 10.0.0.0/16をベースに設計
  3. 配列の順序: [AZ-1a, AZ-1c]の順で統一

カスタマイズ例:

# 大阪リージョンを使う場合
region = "ap-northeast-3"
azs    = ["ap-northeast-3a", "ap-northeast-3c"]

# プロジェクト名を変更
project_name = "my-awesome-app"

5-4. vpc.tf - VPC

ファイルの役割:

  • VPCを作成

コード:

# terraform/phase1-network/vpc.tf

resource "aws_vpc" "main" {
  cidr_block           = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "${var.project_name}-vpc"
  }
}

ポイント:

  1. cidr_block: VPCのIPアドレス範囲
  2. enable_dns_hostnames: DNS名を有効化(ECS Fargateで必要)
  3. enable_dns_support: DNS解決を有効化
  4. tags: リソースに名前を付ける

DNSを有効化する理由:

  • ECS TaskがECRからイメージをpullする際に必要
  • RDSのエンドポイント名を解決する際に必要

5-5. subnet.tf - Subnet × 6

ファイルの役割:

  • Public Subnet × 2、Private Subnet × 2、DB Subnet × 2を作成

コード:

# terraform/phase1-network/subnet.tf

# ==========================================
# Public Subnet × 2
# ==========================================
resource "aws_subnet" "public" {
  count = 2

  vpc_id                  = aws_vpc.main.id
  cidr_block              = var.public_subnet_cidrs[count.index]
  availability_zone       = var.azs[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.project_name}-public-subnet-${count.index + 1}"
  }
}

# ==========================================
# Private Subnet × 2
# ==========================================
resource "aws_subnet" "private" {
  count = 2

  vpc_id            = aws_vpc.main.id
  cidr_block        = var.private_subnet_cidrs[count.index]
  availability_zone = var.azs[count.index]

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

# ==========================================
# DB Subnet × 2
# ==========================================
resource "aws_subnet" "db" {
  count = 2

  vpc_id            = aws_vpc.main.id
  cidr_block        = var.db_subnet_cidrs[count.index]
  availability_zone = var.azs[count.index]

  tags = {
    Name = "${var.project_name}-db-subnet-${count.index + 1}"
  }
}

ポイント:

  1. count = 2: 同じリソースを2つ作成
  2. count.index: 0, 1の順で繰り返す
  3. map_public_ip_on_launch: Public Subnetのみtrue

Subnet別の特徴:

Subnet種別 map_public_ip_on_launch 用途
Public true 起動時にパブリックIPを自動付与
Private false パブリックIPは付与しない
DB false パブリックIPは付与しない

料理で例えると:

  • Public Subnet = ホール(お客さんが見える場所)
  • Private Subnet = 厨房(外から見えない場所)
  • DB Subnet = 倉庫(さらに奥の場所)

5-6. igw.tf - Internet Gateway

ファイルの役割:

  • Internet Gatewayを作成
  • VPCに接続

コード:

# terraform/phase1-network/igw.tf

resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-igw"
  }
}

ポイント:

  1. vpc_id: VPCに紐付ける
  2. シンプルな定義: Internet Gatewayは設定項目が少ない

Internet Gatewayの役割:

  • VPCとインターネットの出入口
  • Public SubnetからインターネットへのアクセスはIGW経由

料理で例えると:

  • Internet Gateway = レストランの正面玄関
  • お客さん(インターネット)はここから出入り

5-7. outputs.tf - 他Phaseで使う値

ファイルの役割:

  • Phase 2以降で使う値を出力

コード:

# terraform/phase1-network/outputs.tf

output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "Public Subnet IDs"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "Private Subnet IDs"
  value       = aws_subnet.private[*].id
}

output "db_subnet_ids" {
  description = "DB Subnet IDs"
  value       = aws_subnet.db[*].id
}

output "azs" {
  description = "Availability Zones"
  value       = var.azs
}

output "igw_id" {
  description = "Internet Gateway ID"
  value       = aws_internet_gateway.main.id
}

ポイント:

  1. output: 他のPhaseから参照できるようにする
  2. [*]: countで作成したリソースをすべて出力
  3. description: 出力の説明

次のPhaseでの使い方:

# phase2-security/data.tf
data "terraform_remote_state" "network" {
  backend = "local"
  config = {
    path = "../phase1-network/terraform.tfstate"
  }
}

# VPC IDを参照
vpc_id = data.terraform_remote_state.network.outputs.vpc_id

6. 実行手順

6-1. ディレクトリ作成

# プロジェクトディレクトリ作成
mkdir -p my-ecs-project/terraform/phase1-network
cd my-ecs-project/terraform/phase1-network

6-2. ファイル作成

上記のコードを7つのファイルに保存:

  • main.tf
  • variables.tf
  • terraform.tfvars
  • vpc.tf
  • subnet.tf
  • igw.tf
  • outputs.tf

6-3. terraform init

Terraformの初期化:

terraform init

実行結果:

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.x.x...

Terraform has been successfully initialized!

やっていること:

  • AWS Providerのダウンロード
  • .terraformディレクトリの作成

6-4. terraform plan

実行計画の確認:

terraform plan

実行結果:

Terraform will perform the following actions:

  # aws_vpc.main will be created
  + resource "aws_vpc" "main" {
      + cidr_block           = "10.0.0.0/16"
      + enable_dns_hostnames = true
      + enable_dns_support   = true
      ...
    }

  # aws_subnet.public[0] will be created
  ...

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

ポイント:

  • Plan: 9 to add: 9個のリソースが作成される
  • エラーがないことを確認

6-5. terraform apply

実際にリソースを作成:

terraform apply

確認メッセージ:

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes  👈 yesと入力

実行結果:

aws_vpc.main: Creating...
aws_vpc.main: Creation complete after 3s [id=vpc-xxxx]
aws_internet_gateway.main: Creating...
aws_subnet.public[0]: Creating...
aws_subnet.public[1]: Creating...
aws_subnet.private[0]: Creating...
aws_subnet.private[1]: Creating...
aws_subnet.db[0]: Creating...
aws_subnet.db[1]: Creating...
...

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

Outputs:

vpc_id = "vpc-0123456789abcdef0"
public_subnet_ids = [
  "subnet-0a1b2c3d4e5f6g7h8",
  "subnet-1a2b3c4d5e6f7g8h9",
]
...

所要時間: 約1-2分


7. 動作確認

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

VPC:

  1. AWSコンソール → VPC → Your VPCs
  2. 「myproject-vpc」が作成されていることを確認
  3. CIDR: 10.0.0.0/16

Subnet:

  1. VPC → Subnets
  2. 6つのSubnetが作成されていることを確認
    • myproject-public-subnet-1, 2
    • myproject-private-subnet-1, 2
    • myproject-db-subnet-1, 2

Internet Gateway:

  1. VPC → Internet Gateways
  2. 「myproject-igw」が作成されていることを確認
  3. State: Attached

7-2. Terraform出力で確認

terraform output

結果:

azs = [
  "ap-northeast-1a",
  "ap-northeast-1c",
]
db_subnet_ids = [
  "subnet-xxx1",
  "subnet-xxx2",
]
igw_id = "igw-xxx"
private_subnet_ids = [
  "subnet-yyy1",
  "subnet-yyy2",
]
public_subnet_ids = [
  "subnet-zzz1",
  "subnet-zzz2",
]
vpc_id = "vpc-xxx"

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

エラー1: AWS認証情報が設定されていない

エラーメッセージ:

Error: No valid credential sources found

原因:

  • AWS CLIの認証情報が未設定

解決策:

aws configure

入力内容:

  • AWS Access Key ID
  • AWS Secret Access Key
  • Default region name: ap-northeast-1
  • Default output format: json

エラー2: CIDR範囲の重複

エラーメッセージ:

Error: creating EC2 Subnet: InvalidSubnet.Conflict

原因:

  • Subnet CIDRが重複している

解決策:

terraform.tfvarsを確認:

# ❌ 悪い例(CIDR重複)
public_subnet_cidrs  = ["10.0.1.0/24", "10.0.1.0/24"]

# ✅ 良い例(CIDR重複なし)
public_subnet_cidrs  = ["10.0.1.0/24", "10.0.2.0/24"]

エラー3: Terraformのバージョンが古い

エラーメッセージ:

Error: Unsupported Terraform Core version

解決策:

# Terraformのバージョン確認
terraform --version

# v1.9.0未満の場合はアップデート
# macOS (Homebrew)
brew upgrade terraform

# Linux
wget https://releases.hashicorp.com/terraform/1.9.x/...

9. 🎯 Phase 1-1完了!

できたこと

✅ VPCの作成
✅ Subnet × 6の作成
✅ Internet Gatewayの作成
✅ Terraformの基本操作の習得

次回予告

第3回: Phase 1-2 - NAT Gateway & Route Table

次回は、Phase 1の後半として以下を作成します:

  • NAT Gateway × 2(Private SubnetからのInternet接続)
  • Route Table × 2(通信経路の設定)
  • Elastic IP × 2(NAT Gateway用の固定IP)

Phase 1-2が完了すると、ネットワーク基盤が完成します!


10. 参考リンク


(続く)

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?