Infrafraction as Code (IaC) を使用している組織は、インフラストラクチャを手動で管理している組織に比べて環境のプロビジョニングが 90% 速くなり、構成関連の停止が 60% 少なくなります。 Terraform は主要な IaC ツールとして台頭しており、3,000 を超えるプロバイダーがあらゆる主要なクラウド プラットフォームと SaaS サービスをサポートしています。
このガイドでは、最初のリソース定義から運用グレードのマルチ環境展開まで、Web アプリケーション、ERP システム、および e コマース プラットフォームでの Terraform の実践的な使用法について説明します。
重要なポイント
- Terraform により、バージョン管理を通じてインフラストラクチャの変更がレビュー可能、テスト可能、元に戻せるようになります
- リモート状態管理により、複数のエンジニアがインフラストラクチャを変更する場合の競合を防止します
- モジュールは再利用可能なパターンをカプセル化し、構成を数百行から数パラメータに削減します
- Terraform Cloud または CI/CD の統合により、安全な変更を実現するための適用前計画の規律が強化されます
SMB に Terraform を使用する理由
手動インフラストラクチャの問題
IaC がなければ、インフラストラクチャの知識は次の場所に存在します。
- 誰も文書化していない AWS コンソールのクリックパス
- SSH コマンドは数か月前に実行されましたが、誰も覚えていません
- サーバー上で直接編集された設定ファイル
- あるエンジニアの「ネットワークがどのように機能するか」に関するメンタル モデル
Terraform を使用すると、インフラストラクチャは Git 内に存在します。すべての変更はプルリクエストです。すべての展開は再現可能です。すべてのエンジニアは全体像を理解できます。
コアコンセプト
| コンセプト | 説明 |
|---|---|
| プロバイダー | クラウドプラットフォーム(AWS、GCP、Azure、Cloudflare)と連携するプラグイン |
| リソース | 単一のインフラストラクチャ コンポーネント (EC2 インスタンス、RDS データベース、S3 バケット) |
| データソース | 既存のインフラストラクチャへの読み取り専用の参照 |
| 変数 | 再利用可能な構成の入力パラメータ |
| 出力 | Terraform 構成からエクスポートされた値 |
| 状態 | Terraform が管理するものとその現在の属性の記録 |
| モジュール | 定義されたインターフェースを持つ再利用可能なリソースのグループ |
最初の Terraform 構成
Web アプリケーション用の AWS VPC と EC2
# providers.tf
terraform {
required_version = ">= 1.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "ecosire-terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
provider "aws" {
region = var.aws_region
}
# variables.tf
variable "aws_region" {
type = string
default = "us-east-1"
}
variable "environment" {
type = string
default = "production"
}
variable "instance_type" {
type = string
default = "t3.large"
}
# main.tf
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 1}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.environment}-public-${count.index + 1}"
}
}
resource "aws_instance" "app" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = aws_subnet.public[0].id
vpc_security_group_ids = [aws_security_group.app.id]
key_name = aws_key_pair.deploy.key_name
root_block_device {
volume_size = 50
volume_type = "gp3"
encrypted = true
}
tags = {
Name = "${var.environment}-app"
Environment = var.environment
}
}
resource "aws_db_instance" "postgres" {
identifier = "${var.environment}-db"
engine = "postgres"
engine_version = "17"
instance_class = "db.t3.medium"
allocated_storage = 50
max_allocated_storage = 200
storage_encrypted = true
db_name = "ecosire"
username = "app"
password = var.db_password
vpc_security_group_ids = [aws_security_group.db.id]
db_subnet_group_name = aws_db_subnet_group.main.name
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "sun:04:00-sun:05:00"
skip_final_snapshot = false
final_snapshot_identifier = "${var.environment}-db-final"
tags = {
Environment = var.environment
}
}
再利用可能なインフラストラクチャ用のモジュール
Web アプリケーション モジュールの作成
# modules/web-app/main.tf
variable "name" {
type = string
}
variable "environment" {
type = string
}
variable "instance_type" {
type = string
default = "t3.medium"
}
variable "vpc_id" {
type = string
}
variable "subnet_ids" {
type = list(string)
}
resource "aws_lb" "app" {
name = "${var.name}-${var.environment}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = var.subnet_ids
}
resource "aws_lb_target_group" "app" {
name = "${var.name}-${var.environment}-tg"
port = 3000
protocol = "HTTP"
vpc_id = var.vpc_id
health_check {
path = "/health"
healthy_threshold = 2
unhealthy_threshold = 3
interval = 30
}
}
resource "aws_autoscaling_group" "app" {
name = "${var.name}-${var.environment}-asg"
min_size = 2
max_size = 10
desired_capacity = 2
vpc_zone_identifier = var.subnet_ids
target_group_arns = [aws_lb_target_group.app.arn]
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
tag {
key = "Name"
value = "${var.name}-${var.environment}"
propagate_at_launch = true
}
}
output "alb_dns_name" {
value = aws_lb.app.dns_name
}
モジュールの使用
# environments/production/main.tf
module "web" {
source = "../../modules/web-app"
name = "ecosire-web"
environment = "production"
instance_type = "t3.large"
vpc_id = module.network.vpc_id
subnet_ids = module.network.public_subnet_ids
}
module "api" {
source = "../../modules/web-app"
name = "ecosire-api"
environment = "production"
instance_type = "t3.large"
vpc_id = module.network.vpc_id
subnet_ids = module.network.public_subnet_ids
}
状態管理
S3 によるリモート状態
# Bootstrap: create the state bucket and DynamoDB table manually or with a separate config
resource "aws_s3_bucket" "terraform_state" {
bucket = "ecosire-terraform-state"
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
DynamoDB を介した状態ロックにより、2 人のエンジニアが terraform apply を同時に実行することがなくなり、状態が破損する可能性があります。
状態ファイルのセキュリティ
Terraform 状態ファイルには、データベース パスワード、API キー、リソース ID などの機密情報が含まれています。保護してください:
- 保存時の暗号化: S3 バケットのバージョン管理 + サーバー側の暗号化
- 転送中の暗号化: 状態アクセスの場合のみ HTTPS
- アクセスを制限: 状態を読み取り/書き込みできるユーザーを制限する IAM ポリシー
- Git には決してコミットしないでください: 状態ファイルをバージョン管理に含めてはなりません
- バージョニングを有効にする: S3 バージョニングにより、破損した状態から回復できます
CI/CD の統合
GitHub アクション Terraform パイプライン
name: Terraform
on:
pull_request:
paths: ['infrastructure/**']
push:
branches: [main]
paths: ['infrastructure/**']
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: terraform init
working-directory: infrastructure/environments/production
- name: Terraform Plan
run: terraform plan -out=tfplan
working-directory: infrastructure/environments/production
- name: Comment PR with plan
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const plan = require('fs').readFileSync('infrastructure/environments/production/tfplan.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Terraform Plan\n\`\`\`\n${plan}\n\`\`\``
});
apply:
needs: plan
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Terraform Apply
run: terraform apply -auto-approve
working-directory: infrastructure/environments/production
マルチ環境戦略
| 環境 | 目的 | インスタンスのサイズ | コスト目標 |
|---|---|---|---|
| 開発 | 機能テスト | t3.micro / t3.small | <$100/月 |
| ステージング | 実稼働前検証 | ミラーの生産(小型) | 生産量の ~30% |
| 制作 | ライブ交通状況 | 荷物に適したサイズ | 最適化された |
Terraform ワークスペースまたは環境ごとに別のディレクトリを使用します。
infrastructure/
modules/
web-app/
database/
network/
environments/
development/
main.tf
terraform.tfvars
staging/
main.tf
terraform.tfvars
production/
main.tf
terraform.tfvars
よくある質問
Terraform と Pulumi --- どちらを選択すべきですか?
宣言型構成を好む運用エンジニアがチームに含まれている場合は、Terraform を使用します。チームが開発者中心で、TypeScript または Python でインフラストラクチャを記述することを好む場合は、Pulumi。 Terraform には、より大きなエコシステムとより多くのコミュニティ モジュールがあります。 Pulumi は初期学習曲線が急になりますが、複雑なロジックに対してより柔軟です。
既存のインフラストラクチャを Terraform にインポートするにはどうすればよいですか?
terraform import を使用して、既存のリソースを Terraform 管理下に置きます。例: terraform import aws_instance.app i-1234567890abcdef0。インポート後、一致する構成を書き込みます。 Terraform 1.5 以降では、一括インポート用の構成ファイル内のインポート ブロックがサポートされています。
Terraform でシークレットをどのように処理すればよいですか?
シークレットを Terraform ファイルに決してコミットしないでください。 terraform.tfvars (Git から除外)、環境変数 (TF_VAR_db_password)、またはシークレット マネージャー (AWS Secrets Manager、HashiCorp Vault) を使用します。機密変数を sensitive = true でマークして、プラン出力に表示されないようにします。
Terraform の管理コストはいくらですか?
Terraform 自体は無料でオープンソースです。 Terraform Cloud には、リモート状態および計画/適用を備えた最大 5 ユーザーの無料利用枠があります。主なコストは、学習曲線 (経験豊富なエンジニアの場合 20 ~ 40 時間) と継続的なメンテナンス (月あたり 2 ~ 4 時間) です。これは、手動のインフラストラクチャ管理で節約された時間によって相殺されます。
次に何が起こるか
Terraform は、自動化されたインフラストラクチャの基盤を提供します。これを、自動展開のために CI/CD パイプライン、運用の可視化のために 監視、復元力のために 災害復旧 と組み合わせます。
インフラストラクチャ自動化コンサルティングについては ECOSIRE にお問い合わせ、完全なロードマップについては 中小企業向け DevOps ガイド をご覧ください。
ECOSIRE によって発行 -- 企業のクラウド インフラストラクチャの自動化を支援します。
執筆者
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
関連記事
買掛金自動化の ROI: 請求書コストを 12 ドルから 2 ドルに削減する裏の実際の数字 (2026 年)
買掛金の自動化により、請求書の処理が 1 件あたり 12 ~ 15 ドルから 3 ドル未満に削減されます。 2026 年の ROI の完全な計算: 金額別の回収額、節約源、および限度額。
2026 年に実際に機能する 25 のビジネス プロセス オートメーションの例 (実稼働環境でビジネス プロセス オートメーションを実行しているチームより)
財務、販売、サポート、運用にわたる 25 の実際のビジネス プロセス自動化の例。AI エージェント、RPA、ワークフローが最も優れている点についての率直なメモが含まれています。
2026 年のクラウド ホスティングの費用はいくらですか?実質価格の内訳 (AWS、Hetzner、DigitalOcean、Odoo.sh)
請求書を支払うチームからの 2026 年の実際のクラウド ホスティング コスト: 月 5 ~ 25 ドルの趣味、月 50 ~ 400 ドルの SMB、隠れた下りとバックアップの料金、予約インスタンスの計算。