【AWSハンズオン】第1回 VPCネットワーク基盤構築

【AWSハンズオン】第1回 VPCネットワーク基盤構築

AWS ECS上でHonoアプリケーションを実行するためのネットワーク基盤をTerraformで構築します。VPC、サブネット、ルーティングの基本設定を通じて、AWSネットワークの基礎を学習できます。

AWS #AWS#ネットワーク

【AWSハンズオン】第1回 VPCネットワーク基盤構築

サムネイル

AWS ECS上でHonoアプリケーションを実行するためのネットワーク基盤をTerraformで構築します。VPC、サブネット、ルーティングの基本設定を通じて、AWSネットワークの基礎を学習できます。

更新日: 8/11/2025

今回はリポジトリに用意された手順に従って環境設定が完了していることを前提とします。TerraformのコマンドはすべてDockerコンテナ内で実行します。

インフラの理解を深めることを目的にしつつ、読者と共に知見を深めるつもりでハンズオン形式にしてまとめていきます。

前提条件

  • プロジェクトのREADME に記載のセットアップが完了していること。
  • Dockerが利用可能である。
  • AWS CLIの認証情報が設定済みである (~/.aws/credentials)。
  • リポジトリをクローンし、.envファイルが設定済みである。
  • setup.sh を実行し、Terraformのバックエンド(S3バケット、DynamoDBテーブル)が作成済みである。

Terraform実行環境の起動

作業を始める前に、Dockerコンテナを起動して中に入ります。

# Dockerイメージをbuild
docker-compose build

# コンテナを起動してbashに入る
docker-compose run --rm terraform

これ以降のコマンドは、すべてこのコンテナ内で実行します。

VPCの基礎知識

VPC (Virtual Private Cloud) は、プライベートなネットワーク空間を構築するサービスです。たとえば従来のオンプレミス環境における自社のデータセンター内ネットワークに相当します。

VPCとは?

どんなものかという定義的な意味で言えば上記で説明した通りですが、WEBアプリケーション開発者の視点から見ると

  • ローカル開発環境のように、サーバー間で自由に通信できるネットワークをクラウド上に構築できます。
  • ファイアウォールやルーティングを設定し、セキュリティを細かく制御できます。
  • リソースをインターネットに公開するか、プライベートなままにするかを柔軟に選択できます。

サブネットとは

サブネットは、VPCのIPアドレス範囲をさらに細かく分割したネットワークセグメントです。役割やセキュリティ要件に応じてリソースをグループ化するために使用します。

2つのサブネットタイプ

パブリックサブネット

  • インターネットゲートウェイへのルートを持ち、インターネットから直接アクセスが可能です。
  • 主に、外部からのリクエストを受け付けるロードバランサーやWebサーバーを配置。

プライベートサブネット

  • インターネットから直接アクセスできないように設定されたサブネットです。
  • アプリケーションサーバーやデータベースなど、セキュリティを重視するリソースを配置。

CIDRブロック

CIDR (Classless Inter-Domain Routing) は、IPアドレスの範囲を効率的に表現するための表記法です。10.0.0.0/16のように表記されます。

10.0.0.0/16 の意味

  • /16 は、32ビットのIPアドレスのうち、先頭の16ビットがネットワーク部であることを示します。
  • 残りの16ビット (32 - 16) がホスト部となり、利用可能なIPアドレス数は 2^16 = 65,536 個です。
  • このVPCでは、10.0.0.0 から 10.0.255.255 までのアドレスが利用できます。

アベイラビリティゾーン(AZ)

AZは、AWSリージョン内に存在する、物理的に独立した1つ以上のデータセンター群です。
よく試験に出てくる内容ですが、マルチAZ構成とは以下の通り。

  • 高可用性: 1つのAZで障害が発生しても、別のAZでサービスを継続できます。
  • 負荷分散: 複数のAZにリソースを分散させることで、負荷を均等に分散できます。
  • 冗長化: データベースなどを複数のAZに配置することで、データの損失を防ぐ役割がある。

今回は東京リージョン (ap-northeast-1) の ap-northeast-1aap-northeast-1c の2つのAZを利用します。

今回作成するネットワーク構成

リソース 説明 数量
VPC アプリケーションのメインとなるネットワーク環境 1個
Internet Gateway VPCとインターネットを接続するためのゲートウェイ 1個
Public Subnet インターネットに公開されるサブネット 2個(マルチAZ)
Private Subnet インターネットから隔離されたサブネット 2個(マルチAZ)
Route Table 通信経路を制御するテーブル 3個(パブリック用×1, プライベート用×2)

アーキテクチャ図

作成されるネットワーク構成は以下の通りです。
ここら辺苦手なのでmermaidで吐き出しました。

スクリーンショット 2025-07-13 15.02.46.png

CIDR設計

VPC CIDR: 10.0.0.0/16
├── Public Subnet A  (10.0.1.0/24)  - ap-northeast-1a
├── Public Subnet C  (10.0.2.0/24)  - ap-northeast-1c
├── Private Subnet A (10.0.11.0/24) - ap-northeast-1a
└── Private Subnet C (10.0.12.0/24) - ap-northeast-1c

各サブネットには /24 のCIDRブロックを割り当てます。

Terraformコードの実装

プロバイダー設定

すべてのリソースに共通のタグをつけて管理しやすくしておきます。

# terraform/provider.tf
provider "aws" {
  region = var.aws_region

  default_tags {
    tags = {
      Project     = var.project_name
      Environment = var.environment
      ManagedBy   = "terraform"
    }
  }
}

変数定義

設定を一元管理するための変数を定義します。

# terraform/variables.tf
variable "project_name" {
  description = "プロジェクト名"
  type        = string
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

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

variable "availability_zones" {
  description = "使用するアベイラビリティゾーン"
  type        = list(string)
  default     = ["ap-northeast-1a", "ap-northeast-1c"]
}

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

project_name変数について

project_name.envファイル内のTF_VAR_project_nameで設定することが前提です。もし設定されていない場合、Terraform実行時に入力を求められます。ヒューマンエラー発生ポイントなので環境変数に任せましょう。

VPCとInternet Gateway

ネットワークの基礎となるVPCと、インターネット接続の窓口となるInternet Gatewayを作成します。

# terraform/network.tf

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

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

# Internet Gateway
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

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

パブリックサブネット

AZの数だけパブリックサブネットを作成します。また、インターネットへの通信を可能にするルートテーブルを作成し、各サブネットに関連付けます。

# terraform/network.tf

# Public Subnets
resource "aws_subnet" "public" {
  count = length(var.availability_zones)

  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.${count.index + 1}.0/24"
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.project_name}-${var.environment}-public-subnet-${substr(var.availability_zones[count.index], -1, 1)}"
    Type = "Public"
  }
}

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

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

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

# Public Subnet Route Table Association
resource "aws_route_table_association" "public" {
  count = length(aws_subnet.public)

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

プライベートサブネット

同様にプライベートサブネットを作成します。こちらはインターネットに直接接続しないため、現時点ではルートテーブルに特別なルートは設定しません。

# terraform/network.tf

# Private Subnets
resource "aws_subnet" "private" {
  count = length(var.availability_zones)

  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${count.index + 11}.0/24"
  availability_zone = var.availability_zones[count.index]

  tags = {
    Name = "${var.project_name}-${var.environment}-private-subnet-${substr(var.availability_zones[count.index], -1, 1)}"
    Type = "Private"
  }
}

# Private Route Tables (AZごとに作成)
resource "aws_route_table" "private" {
  count = length(var.availability_zones)

  vpc_id = aws_vpc.main.id

  tags = {
    Name = "${var.project_name}-${var.environment}-private-rt-${substr(var.availability_zones[count.index], -1, 1)}"
  }
}

# Private Subnet Route Table Association
resource "aws_route_table_association" "private" {
  count = length(aws_subnet.private)

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

出力

他のTerraformモジュールや外部から参照できるように、作成したリソースのIDなどを出力します。

# terraform/outputs.tf
output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "パブリックサブネットIDのリスト"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "プライベートサブネットIDのリスト"
  value       = aws_subnet.private[*].id
}

リソースを作成

Dockerコンテナ内で以下のコマンドを実行し、インフラを構築します。

# terraformディレクトリへ移動
cd terraform

# 初期化 (バックエンド設定ファイルを指定)
terraform init -backend-config=backend.hcl

# 実行計画の確認
terraform plan

# リソースの作成
terraform apply

applyコマンド実行後、確認を求められたら yes と入力します。

作成結果の確認

applyが完了したら、outputで定義した値を確認できます。

# VPC IDの表示
terraform output vpc_id

# サブネットIDのリスト表示
terraform output public_subnet_ids
terraform output private_subnet_ids

動作確認

AWS Management Consoleでの確認

AWS Management Consoleにログインし、VPCサービス画面で以下のリソースが正しく作成されていることを確認します。

VPCダッシュボード

  • .envで設定したプロジェクト名のVPCが作成されていること。
  • CIDR範囲が 10.0.0.0/16 であること。

サブネット

  • 合計4つのサブネット(パブリック×2、プライベート×2)が作成されていること。
  • 各サブネットが指定したAZ (ap-northeast-1a, ap-northeast-1c) に配置されていること。

ルートテーブル

  • パブリック用のルートテーブルに、Internet Gateway (igw-xxxx) へのルート (0.0.0.0/0) が設定されていること。
  • プライベート用のルートテーブルがAZごとに作成されていること。

現段階ではサブネット内にEC2インスタンスなどのリソースが存在しないため、疎通確認は次回以降で行います。

次のステップ

次回、ここで構築したネットワーク基盤の上にセキュリティ層を追加します。

  • Security Groups: ALB、ECS、RDSといった各リソースの通信を制御するファイアウォール
  • NAT Gateway: プライベートサブネット内のリソースが、外部のAPIやアップデートを取得するためのアウトバウンド通信経路

検索

検索条件に一致する記事が見つかりませんでした