更新: 2026年03月 · 12 分で読める · 5,799 文字
Terraformで始めるAWSインフラ構築:初日から本番環境まで
この記事では、Terraformの基本概念から実践的なAWSリソース構築まで、すぐに仕事で活用できる内容を段階的に解説します。Infrastructure as Code(IaC)の考え方を理解し、手動運用から脱却するための具体的な手順を学べます。
Terraformがなぜ必要か:従来の運用との違い
AWSリソースを管理する際、多くの企業は以下の課題に直面しています:
- AWS マネジメントコンソールからの手動設定による人為的ミス
- 環境構築手順のドキュメント作成と更新の負担
- 開発環境と本番環境の設定差異の発生
- インフラ変更履歴の追跡困難さ
Terraformは、これらの問題をコード化することで解決します。CloudFormationやAWS CDKなど他の IaC ツールも存在しますが、Terraformはマルチクラウド対応と直感的な設定記法が特徴で、業界での採用例が最も多いです。
Terraformの基本構造をつかむ
インストールと初期設定
まずは開発環境にTerraformをインストールしましょう。以下のコマンドで最新バージョンを取得できます。
# macOSの場合(Homebrewを使用)
brew install terraform
# インストール確認
terraform version
# Terraformの補完機能を有効化(Zshの場合)
terraform -install-autocomplete
Windows環境の場合は公式インストールガイドを参照してください。
Terraformの設定ファイル形式
Terraformは .tf ファイルでインフラストラクチャを定義します。基本的なファイル構成は以下の通りです:
# main.tf
# メインのリソース定義ファイル
provider "aws" {
region = "ap-northeast-1"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "terraform-example"
}
}
# variables.tf
# 変数定義ファイル
variable "aws_region" {
description = "AWS region"
type = string
default = "ap-northeast-1"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
# outputs.tf
# 出力値定義ファイル
output "instance_public_ip" {
description = "Public IP of the instance"
value = aws_instance.example.public_ip
}
実践的なAWSリソース構築:VPC+EC2の例
プロジェクトの初期化
新しいディレクトリを作成してプロジェクトを開始します:
mkdir terraform-aws-project
cd terraform-aws-project
# Terraformの初期化
# .terraformディレクトリと .terraform.lock.hcl ファイルが生成されます
terraform init
VPCとEC2インスタンスの完全な構成例
# main.tf
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
# VPC作成
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "${var.environment}-vpc"
}
}
# パブリックサブネット
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "${var.aws_region}a"
map_public_ip_on_launch = true
tags = {
Name = "${var.environment}-public-subnet"
}
}
# インターネットゲートウェイ
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.environment}-igw"
}
}
# ルートテーブル
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.environment}-public-rt"
}
}
# ルートテーブルの関連付け
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# セキュリティグループ
resource "aws_security_group" "web" {
name = "${var.environment}-web-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.ssh_cidr_block]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.environment}-web-sg"
}
}
# EC2インスタンス
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux_2.id
instance_type = var.instance_type
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = base64encode(file("${path.module}/user_data.sh"))
tags = {
Name = "${var.environment}-web-server"
}
}
# Amazon Linux 2の最新AMIを取得
data "aws_ami" "amazon_linux_2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
}
# variables.tf
variable "aws_region" {
description = "AWS region"
type = string
default = "ap-northeast-1"
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
variable "ssh_cidr_block" {
description = "CIDR block for SSH access"
type = string
default = "0.0.0.0/0" # 本番環境では必ず制限してください
}
# outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "instance_public_ip" {
description = "Public IP address of EC2 instance"
value = aws_instance.web.public_ip
}
output "instance_id" {
description = "ID of EC2 instance"
value = aws_instance.web.id
}
output "security_group_id" {
description = "ID of security group"
value = aws_security_group.web.id
}
# user_data.sh
#!/bin/bash
set -e
# システム更新
yum update -y
# Webサーバーをインストール
yum install -y httpd
# サービスを開始
systemctl start httpd
systemctl enable httpd
# 簡単なテストページを作成
cat > /var/www/html/index.html << 'EOF'
Terraform Demo
Terraformで構築されたサーバーです
Infrastructure as Codeの力を体験してください!
EOF
計画と実行
リソースを作成する前に、必ず terraform plan コマンドで変更内容を確認してください:
# 変更予定を確認
terraform plan -out=tfplan
# 問題がなければリソースを作成
terraform apply tfplan
# または直接実行(対話的に確認)
terraform apply
よくあるハマりポイントと解決策
AWS認証情報が見つからないエラー
Error: error configuring Terraform AWS Provider: no valid credential sources for Terraform AWS Provider found というエラーが出た場合、以下を確認してください:
# AWS CLIの認証情報が正しく設定されているか確認
aws sts get-caller-identity
# 環境変数で認証情報を指定する場合
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_REGION="ap-northeast-1"
terraform init
terraform apply
状態ファイルの競合
複数人で Terraform を使用する場合、ローカルの terraform.tfstate ファイルではなく、リモートバックエンド(S3など)を使用してください:
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
リソースが予期せず削除される
変数を変更するときは、-var オプションで値を明示的に指定しないと、default 値で上書きされる場合があります:
# terraform.tfvars ファイルで変数を定義すると安全です
environment = "prod"
instance_type = "t3.small"
ssh_cidr_block = "203.0.113.0/24"
# コマンドから実行
terraform apply -var-file="terraform.tfvars"
運用時に必須のコマンド
# 現在の状態を確認
terraform show
# 特定リソースの詳細を表示
terraform show aws_instance.web
# 状態ファイルを更新(リソースを手動変更した場合)
terraform refresh
# リソースを削除
terraform destroy
# 特定リソースのみ削除
terraform destroy -target=aws_instance.web
# 状態ファイルから特定リソースを削除
terraform state rm aws_instance.web
# 状態ファイルをインポート(既存リソースを Terraform で管理する場合)
terraform import aws_instance.web i-1234567890abcdef0
Terraform を使うべき場面・使うべきでない場面
使うべき場面
- 複数環境(開発・ステージング・本番)を同じ構成で管理する
- インフラ変更履歴をバージョン管理したい
- 複数のクラウドプロバイダを組み合わせる
- チーム開発でインフラコードをレビューしたい
使うべきでない場面
- 一度限りの簡単なテスト環境構築(マネジメントコンソールで十分)
- 頻繁に手動調整が必要な運用フロー
- Terraform の学習に時間をかけられない急ぎのプロジェクト
テスト環境での動作確認
この記事の内容は以下の環境で動作確認しました:
- Terraform v1.6.4
- AWS Provider v5.30
- macOS 13 / Amazon Linux 2
よくある質問
おすすめDevOpsリソース
- Docker Documentation Official Docker and Docker Compose reference.
- Kubernetes Docs Official K8s documentation. Great for understanding concepts.
- GitHub Actions Docs Official guide for CI/CD workflows.