今回はリポジトリに用意された手順に従って環境設定が完了していることを前提とします。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-1a
と ap-northeast-1c
の2つのAZを利用します。
今回作成するネットワーク構成
リソース | 説明 | 数量 |
---|---|---|
VPC | アプリケーションのメインとなるネットワーク環境 | 1個 |
Internet Gateway | VPCとインターネットを接続するためのゲートウェイ | 1個 |
Public Subnet | インターネットに公開されるサブネット | 2個(マルチAZ) |
Private Subnet | インターネットから隔離されたサブネット | 2個(マルチAZ) |
Route Table | 通信経路を制御するテーブル | 3個(パブリック用×1, プライベート用×2) |
アーキテクチャ図
作成されるネットワーク構成は以下の通りです。
ここら辺苦手なのでmermaidで吐き出しました。
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やアップデートを取得するためのアウトバウンド通信経路