# TerraformによるAWSインフラ構築
はじめに
AWSコンソールで手動でクラウドインフラを管理するのは、ミスが起こりやすくスケールしません。HashiCorpのTerraformを使えば、インフラストラクチャをコードとして定義(IaC)でき、バージョン管理、再現性、自動化が実現します。
このチュートリアルでは、以下の本番対応AWS環境を構築します:
- パブリックとプライベートサブネットを持つカスタムVPC
- セキュリティグループ付きのEC2ウェブサーバー
- プライベートサブネット内のRDS MySQLデータベース
- リソースへの簡単アクセスのための出力値
- IAM認証情報を持つAWSアカウント
- Terraform >= 1.6 がインストール済み
- AWSネットワーキングの基本的な理解
前提条件
ステップ1: Terraformのインストールと設定
# Terraformをインストール (macOS)
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# インストールを確認
terraform version
# AWS認証情報を設定
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_REGION="ap-northeast-1"
ステップ2: プロジェクト構造
以下のディレクトリ構造を作成します:
terraform-aws-demo/
├── main.tf # ルートモジュール
├── variables.tf # 入力変数
├── outputs.tf # 出力値
├── terraform.tfvars # 変数の値
├── modules/
│ ├── vpc/
│ ├── ec2/
│ └── rds/
ステップ3: VPCモジュールの定義
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
Environment = var.environment
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-${count.index + 1}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnet_cidrs[count.index]
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.project_name}-private-${count.index + 1}"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
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
}
}
ステップ4: EC2モジュールの定義
# modules/ec2/main.tf
resource "aws_security_group" "web" {
name_prefix = "${var.project_name}-web-"
vpc_id = var.vpc_id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.ssh_cidr]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
subnet_id = var.subnet_id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd php php-mysqlnd
systemctl start httpd
systemctl enable httpd
EOF
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.project_name}-web"
}
}
ステップ5: RDSモジュールの定義
# modules/rds/main.tf
resource "aws_db_subnet_group" "main" {
name = "${var.project_name}-db-subnet"
subnet_ids = var.private_subnet_ids
}
resource "aws_security_group" "db" {
name_prefix = "${var.project_name}-db-"
vpc_id = var.vpc_id
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [var.web_sg_id]
}
}
resource "aws_db_instance" "main" {
identifier = "${var.project_name}-db"
engine = "mysql"
engine_version = "8.0"
instance_class = var.db_instance_class
allocated_storage = 20
storage_encrypted = true
db_name = var.db_name
username = var.db_username
password = var.db_password
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.db.id]
skip_final_snapshot = true
}
ステップ6: デプロイ
# 初期化
terraform init
# プレビュー
terraform plan
# 適用
terraform apply -auto-approve
# 出力を確認
terraform output
# 削除(課金を避けるため!)
terraform destroy -auto-approve
ベストプラクティス
terraform fmt と terraform validate を常に実行terraform.tfvars に入れず、環境変数やAWS Secrets Managerを使用まとめ
本チュートリアルで学んだこと:
Terraformにより、インフラの再現性と監査可能性が確保されます。CI/CDパイプラインと組み合わせて完全自動化を実現しましょう。