基本機能

ベストプラクティス

Terraformを効果的に使用するためのベストプラクティスを紹介します。これらの推奨事項に従うことで、保守性が高く、安全で、スケーラブルなインフラストラクチャコードを作成できます。
最終更新: 2026/2/17

ベストプラクティス

Terraformを効果的に使用するためのベストプラクティスを紹介します。これらの推奨事項に従うことで、保守性が高く、安全で、スケーラブルなインフラストラクチャコードを作成できます。

コード構成

1. ファイルの分割

関連するリソースをファイルごとに分割します。

project/
├── main.tf          # プロバイダーとメインリソース
├── variables.tf     # 変数の定義
├── outputs.tf       # 出力の定義
├── versions.tf      # Terraformとプロバイダーのバージョン
├── network.tf       # ネットワーク関連リソース
├── compute.tf       # コンピュートリソース
├── database.tf      # データベースリソース
└── security.tf      # セキュリティ関連リソース

2. 環境ごとにディレクトリを分離

terraform/
├── modules/         # 再利用可能なモジュール
│   ├── vpc/
│   ├── ec2/
│   └── rds/
├── environments/    # 環境ごとの設定
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── terraform.tfvars
│   └── prod/
│       ├── main.tf
│       ├── variables.tf
│       └── terraform.tfvars
└── global/          # 全環境共通のリソース
    └── iam/

命名規則

1. リソース名

明確で一貫性のある命名規則を使用します。

# 良い例
resource "aws_instance" "web_server" {
  # ...
}

resource "aws_s3_bucket" "application_logs" {
  # ...
}

# 悪い例
resource "aws_instance" "i1" {
  # ...
}

resource "aws_s3_bucket" "bucket" {
  # ...
}

2. タグの標準化

すべてのリソースに一貫したタグを付けます。

locals {
  common_tags = {
    Project     = var.project_name
    Environment = var.environment
    ManagedBy   = "Terraform"
    Owner       = var.owner
    CostCenter  = var.cost_center
  }
}

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
  
  tags = merge(
    local.common_tags,
    {
      Name = "${var.project_name}-web-${var.environment}"
      Role = "WebServer"
    }
  )
}

変数の管理

1. 変数の型を明示

# 良い例
variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro"
}

variable "availability_zones" {
  description = "List of availability zones"
  type        = list(string)
}

variable "tags" {
  description = "Tags to apply to resources"
  type        = map(string)
  default     = {}
}

# 悪い例(型指定なし)
variable "instance_type" {
  default = "t2.micro"
}

2. 変数の検証

variable "environment" {
  description = "Environment name"
  type        = string
  
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  
  validation {
    condition     = can(regex("^t[2-3]\\.", var.instance_type))
    error_message = "Instance type must be a t2 or t3 instance."
  }
}

3. 機密情報の扱い

variable "db_password" {
  description = "Database password"
  type        = string
  sensitive   = true
}

# terraform.tfvarsには含めない
# 環境変数で渡す
# export TF_VAR_db_password="secure-password"

状態管理

1. リモートバックエンドの使用

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-lock"
  }
}

2. 状態ファイルの保護

# S3バケットの設定例
resource "aws_s3_bucket" "terraform_state" {
  bucket = "my-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_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

セキュリティ

1. 最小権限の原則

# IAMポリシーの例
resource "aws_iam_role_policy" "ec2_policy" {
  name = "ec2-policy"
  role = aws_iam_role.ec2_role.id
  
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "s3:GetObject",
          "s3:ListBucket"
        ]
        Resource = [
          aws_s3_bucket.app_bucket.arn,
          "${aws_s3_bucket.app_bucket.arn}/*"
        ]
      }
    ]
  })
}

2. セキュリティグループの制限

# 良い例:特定のIPからのみアクセスを許可
resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Security group for web servers"
  vpc_id      = aws_vpc.main.id
  
  ingress {
    description = "HTTPS from office"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["203.0.113.0/24"]  # オフィスのIPアドレス
  }
}

# 悪い例:すべてのポートを開放
resource "aws_security_group" "bad" {
  name = "bad-sg"
  
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]  # 避けるべき
  }
}

3. 機密データの暗号化

resource "aws_db_instance" "main" {
  identifier        = "mydb"
  engine            = "postgres"
  instance_class    = "db.t3.micro"
  allocated_storage = 20
  
  # 暗号化を有効化
  storage_encrypted = true
  kms_key_id        = aws_kms_key.db.arn
  
  # パブリックアクセスを無効化
  publicly_accessible = false
}

モジュールの使用

1. DRY原則(Don't Repeat Yourself)

# 悪い例:同じコードを繰り返す
resource "aws_instance" "web1" {
  ami           = "ami-xxxxx"
  instance_type = "t2.micro"
  # ... 多くの設定 ...
}

resource "aws_instance" "web2" {
  ami           = "ami-xxxxx"
  instance_type = "t2.micro"
  # ... 同じ設定を繰り返す ...
}

# 良い例:モジュールを使用
module "web_servers" {
  source = "./modules/ec2"
  
  count         = 2
  ami           = "ami-xxxxx"
  instance_type = "t2.micro"
}

2. モジュールのバージョン管理

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"  # メジャーバージョンを固定
  
  name = "my-vpc"
  cidr = "10.0.0.0/16"
}

コードの品質

1. フォーマットの統一

# コードのフォーマット
terraform fmt -recursive

# CI/CDでチェック
terraform fmt -check -recursive

2. 検証の実行

# 構文チェック
terraform validate

# セキュリティスキャン(tfsec)
tfsec .

# リンティング(tflint)
tflint

3. ドキュメントの作成

# variables.tf
variable "instance_type" {
  description = "EC2 instance type. Recommended: t2.micro for dev, t3.medium for prod"
  type        = string
  default     = "t2.micro"
}

# outputs.tf
output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.web.id
}

依存関係の管理

1. 明示的な依存関係

resource "aws_instance" "web" {
  ami           = "ami-xxxxx"
  instance_type = "t2.micro"
  
  # 明示的な依存関係
  depends_on = [aws_s3_bucket.logs]
}

2. データソースの活用

# 既存のリソースを参照
data "aws_vpc" "existing" {
  id = var.vpc_id
}

resource "aws_subnet" "new" {
  vpc_id     = data.aws_vpc.existing.id
  cidr_block = "10.0.1.0/24"
}

ライフサイクル管理

1. 破壊的な変更の防止

resource "aws_db_instance" "main" {
  identifier = "mydb"
  # ... その他の設定 ...
  
  lifecycle {
    prevent_destroy = true
  }
}

2. ダウンタイムの最小化

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
  
  lifecycle {
    create_before_destroy = true
  }
}

3. 特定の変更を無視

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
  
  tags = {
    Name = "WebServer"
  }
  
  lifecycle {
    ignore_changes = [
      tags,           # タグの変更を無視
      user_data,      # User Dataの変更を無視
    ]
  }
}

CI/CDとの統合

1. 自動化されたワークフロー

# GitHub Actions の例
name: Terraform

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2
        
      - name: Terraform Format
        run: terraform fmt -check -recursive
        
      - name: Terraform Init
        run: terraform init
        
      - name: Terraform Validate
        run: terraform validate
        
      - name: Terraform Plan
        run: terraform plan
        
      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve

2. プルリクエストでのプラン確認

- name: Terraform Plan
  run: terraform plan -no-color
  continue-on-error: true
  
- name: Comment PR
  uses: actions/github-script@v6
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: 'Terraform Plan:\n```\n${{ steps.plan.outputs.stdout }}\n```'
      })

パフォーマンスの最適化

1. ターゲットの使用

# 特定のリソースのみ更新
terraform apply -target=aws_instance.web

# 複数のターゲットを指定
terraform apply -target=aws_instance.web -target=aws_security_group.web

2. 並列処理の調整

# 並列処理数を増やす
terraform apply -parallelism=20

# 並列処理数を減らす(APIレート制限対策)
terraform apply -parallelism=5

エラーハンドリング

1. 条件付きリソース作成

resource "aws_instance" "web" {
  count = var.create_instance ? 1 : 0
  
  ami           = var.ami_id
  instance_type = var.instance_type
}

2. デフォルト値の設定

locals {
  instance_type = var.instance_type != "" ? var.instance_type : "t2.micro"
}

次のステップ

ベストプラクティスを理解したら、トラブルシューティングについて学びましょう。

参考リンク

© 2026 IBM Corporation. Licensed under CC BY 4.0.