技術深掘り

Terraform 本番運用アーキテクチャ設計論 (2025年版): 宣言的 IaC の実践から大規模プロジェクトの統治まで

テックリード/シニアエンジニア向け。Terraform の基本から、チーム開発で必須となるリモート状態管理 (tfstate)、再利用可能なモジュール設計、CI/CD パイプラインでの自動化、そして Vault や sops を用いた機密情報管理まで、本番環境で Terraform を統治するための設計論を深掘りします。

佐藤 裕介

佐藤 裕介

大規模サービスのインフラ運用経験10年以上。Kubernetes、Terraform、CI/CDパイプライン構築を得意とし、信頼性の高いシステム基盤を提供します。

Terraform IaC AWS DevOps Infrastructure Architecture GitOps Security
Terraform 本番運用アーキテクチャ設計論 (2025年版): 宣言的 IaC の実践から大規模プロジェクトの統治まで

はじめに: terraform apply の先にある、本番運用の複雑性

Terraform は、クラウドインフラをコードで管理するための強力なツールです。しかし、個人の開発環境で terraform apply を実行することと、複数人のチームで本番環境のインフラを安全かつ効率的に管理し続けることの間には、深い溝が存在します。

もしあなたが、以下の項目にピンときたら、この記事はあなたに必要な記事かもしれません。

  • チームメンバーがローカルで apply した結果、terraform.tfstate ファイルがコンフリクトし、インフラの状態が不整合に陥った経験がある
  • 環境ごと (dev, stg, prd) に微妙に異なる設定を、コードのコピペで管理しており、変更に手間とリスクが伴っている
  • 本番環境のデータベースパスワードなどの機密情報を、どのようにして安全に Terraform コードで管理すべきか、明確な答えを持っていない
  • Pull Request でのインフラ変更レビューが、terraform plan の結果を目視で確認するだけの形骸化したものになっている

本稿は、Terraform の基本的な resource 構文を解説するチュートリアルではありません。インフラの変更を、アプリケーションコードと同様に、再現可能で、レビュー可能で、テスト可能にするためのアーキテクチャ設計論を深掘りします。この記事を読み終える頃には、あなたは Terraform を単なるツールとしてではなく、インフラのライフサイクル全体を統治するための強力なフレームワークとして使いこなすための、確かな知見を手にしているでしょう。


目次

  1. チーム開発の基本: リモート状態管理とステートロック
  2. コードの再利用性と保守性: モジュール設計戦略
  3. マルチ環境の統治: プロジェクト構成と Workspace
  4. IaC のセキュリティ: 機密情報の安全な管理
  5. 自動化による統治: CI/CD パイプラインの設計
  6. 結論: プロジェクトフェーズで進化する Terraform アーキテクチャ

1. チーム開発の基本: リモート状態管理とステートロック

Terraform がインフラの状態を管理するために使用する terraform.tfstate ファイルは、チーム開発における最大のリスク源となり得ます。ローカルでこのファイルを管理していると、誰かが apply した変更が他のメンバーに共有されず、意図しないリソースの破壊や不整合を引き起こします。

この問題を解決するのが、リモートバックエンドです。状態ファイルを S3 のような共有ストレージに保存し、チーム全員が同じ状態を参照するようにします。

さらに、同時に複数のメンバーが apply を実行するのを防ぐために、ステートロックの仕組みが不可欠です。AWS 環境では、DynamoDB を使ってこれを実現します。

graph TD
    subgraph "開発者 A"
        DevA_PC -- "terraform apply" --> LockA{Acquire Lock on DynamoDB}
    end
    
    subgraph "開発者 B"
        DevB_PC -- "terraform apply" --> LockB{Acquire Lock on DynamoDB}
    end

    subgraph "AWS"
        S3["S3 Bucket (tfstate)"]
        DDB["DynamoDB Table (Lock)"]
    end

    LockA -- "Success" --> UpdateStateA("Update tfstate on S3")
    LockB -- "Failed (State is Locked)" --> Wait
    
    UpdateStateA --> S3
    DDB -- "Provides Lock" --> LockA

実装: backend.tf

この設定は、backend.tf というファイルに記述するのが慣例です。

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

SRE としての判断: リモートバックエンドとステートロックの設定は、Terraform をチームで利用するためのゼロステップです。これを設定せずに本番運用することは、コードをバージョン管理しないことと同義の、極めて危険な行為です。


2. コードの再利用性と保守性: モジュール設計戦略

VPC、サブネット、セキュリティグループといった定型的なリソースの組み合わせは、多くのプロジェクトで繰り返し登場します。これらのコードをコピペで管理すると、一つの修正(例: セキュリティグループのルール変更)を全ての箇所に反映する必要があり、漏れやミスの温床となります。

モジュールは、関連するリソース群を一つの再利用可能なコンポーネントとしてカプセル化する仕組みです。

モジュールの基本構造

/modules/vpc/
  ├── main.tf      # VPC, Subnet, IGW などのリソースを定義
  ├── variables.tf # 入力変数 (例: VPC の CIDR ブロック) を定義
  └── outputs.tf   # 出力 (例: 作成された VPC ID, Subnet ID) を定義

モジュールの利用

ルートの main.tf から、このモジュールを呼び出します。

module "my_vpc" {
  source = "./modules/vpc"

  vpc_cidr = "10.0.0.0/16"
  app_name = "my-production-app"
  
  # ... other variables
}

resource "aws_instance" "my_app" {
  # モジュールの output を参照
  subnet_id = module.my_vpc.public_subnet_id
  # ...
}

意思決定指針:

  • いつモジュールを作るか?: 同じようなリソースの組み合わせを 3回以上記述したら、それはモジュール化の強力な候補です。
  • 良いモジュールの条件:
    • 単一責任の原則: 1つのモジュールは、1つの関心事(例: VPC、RDS、ECS サービス)に集中する。
    • 設定の柔軟性: variables を通じて、利用側で挙動を柔軟にカスタマイズできるようにする。
    • 明確な outputs: モジュールが作成したリソースのうち、外部から参照する必要があるものだけを outputs として公開する。

3. マルチ環境の統治: プロジェクト構成と Workspace

プロジェクトがスケールするにつれて、本番 (production)、ステージング (staging)、開発 (development) といった複数環境の管理は、単なる設定値の変更から、アーキテクチャ上の複雑な課題へと進化します。環境ごとにコードをコピー&ペーストするような素朴なアプローチは、メンテナンス性を著しく損ない、一つの変更を複数箇所に反映させる手間と、設定ミスや環境間の不整合といったリスクを増大させます。ここでの中心的な課題は、「いかにして環境間の分離を徹底し、誤操作のリスクを排除しつつ、コードの再利用性を最大化して保守性と一貫性を担保するか」という点にあります。本章では、この課題を解決するためのアーキテクチャパターンを、ディレクトリベースの環境分離から Terraform Workspace のアンチパターンまで深掘りします。

ディレクトリによる環境分離 (推奨)

最も堅牢で分かりやすい方法は、環境ごとにディレクトリを分離するアプローチです。

/terraform/
  ├── modules/          # 共有モジュール
  │   └── vpc/
  ├── environments/
  │   ├── development/
  │   │   ├── main.tf
  │   │   ├── backend.tf # dev 用の tfstate パスを指定
  │   │   └── terraform.tfvars
  │   ├── staging/
  │   │   ├── main.tf
  │   │   ├── backend.tf # stg 用の tfstate パスを指定
  │   │   └── terraform.tfvars
  │   └── production/
  │       ├── main.tf
  │       ├── backend.tf # prd 用の tfstate パスを指定
  │       └── terraform.tfvars
  └── common.tfvars
  • メリット: 各環境の状態 (tfstate) が完全に分離されるため、dev での作業が prd に影響を与えるリスクを物理的に排除できます。
  • デメリット: コードの重複が増える傾向にあります。terragrunt などのツールは、この重複を減らすために common.tfvars のような共通変数をインクルードする機能を提供します。

Terraform Workspace (非推奨)

Terraform には workspace という、単一のディレクトリで複数の状態を管理する機能がありますが、多くのケースでアンチパターンとされています。

  • 問題点: terraform workspace select production のようなコマンド一発で環境が切り替わるため、ヒューマンエラーで本番環境を意図せず変更・破壊するリスクが非常に高いです。

4. IaC のセキュリティ: 機密情報の安全な管理

データベースのパスワードや API キーといった機密情報を、Git で管理される .tf ファイルに直接書き込むことは絶対に避けなければなりません。

推奨される戦略

  • 外部の Secret 管理ストアを利用する: AWS Secrets Manager, HashiCorp Vault, SOPS (Mozilla) などを利用し、機密情報自体は Git の管理外に置きます。
  • データソースとして参照: Terraform からは、これらのストアに必要な Secret を data ソースとして実行時に読み込み、リソースに渡します。
# AWS Secrets Manager から DB パスワードを取得
data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "my-app/rds-password"
}

resource "aws_db_instance" "default" {
  # ...
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

このアプローチにより、Terraform を実行する CI/CD 環境の IAM ロールにのみ Secret へのアクセス権を付与し、開発者のローカル環境からは本番の Secret にアクセスできないようにする、といった権限管理が可能になります。


5. 自動化による統治: CI/CD パイプラインの設計

手動での terraform apply はヒューマンエラーの元です。インフラの変更は、アプリケーションコードと同様に、CI/CD パイプラインを通じて自動的に適用されるべきです。

GitHub Actions を用いたパイプライン例

graph TD
    A["開発者がPRを作成"] --> B("GitHub Actions Trigger (on pull_request)");
    subgraph "CI Job"
        B --> C["terraform fmt & validate"];
        C --> D["terraform plan"];
        D --> E["Plan結果をPRにコメント"];
    end
    E --> F{"人間のレビューと承認"};
    F -- "Approve & Merge" --> G["mainブランチにマージ"];
    G --> H("GitHub Actions Trigger (on push to main)");
    subgraph "CD Job"
        H --> I["terraform apply"];
    end
    I --> J["インフラに適用"];

実装のポイント (.github/workflows/terraform.yml)

# ...
jobs:
  plan:
    name: 'Terraform Plan'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3

      # AWS 認証
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::ACCOUNT_ID:role/github-actions-terraform-role
          aws-region: ap-northeast-1

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan -out=tfplan

  apply:
    name: 'Terraform Apply'
    runs-on: ubuntu-latest
    needs: plan
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    steps:
      # ... (plan job と同様のセットアップ) ...
      - name: Terraform Apply
        run: terraform apply -auto-approve tfplan
  • OIDC の活用: AWS のクレデンシャルを secrets に保存する代わりに、GitHub Actions と AWS の間で OIDC (OpenID Connect) 連携を設定し、一時的な認証情報を利用するのが現在のベストプラクティスです。
  • 静的解析: tfseccheckov といったツールをパイプラインに組み込むことで、セキュリティのベストプラクティスに違反していないかを自動的にチェックできます。

6. 結論: プロジェクトフェーズで進化する Terraform アーキテクチャ

Terraform は、単にインフラをプロビジョニングするツールではありません。それは、アプリケーションコードに求められるのと同等の規律(レビュー、テスト、バージョン管理)をインフラにもたらし、チームの成長とプロジェクトの複雑化に対応しながら、インフラの信頼性と変更速度を両立させるためのアーキテクチャフレームワークです。

冒頭で提示した「tfstateがコンフリクトする」「環境間の設定をコピペしている」「機密情報の管理が曖昧」「PRレビューが形骸化している」といった課題は、場当たり的な運用ルールの結果生じる典型的な「痛み」です。本稿で解説したアーキテクチャパターンは、これらの課題に体系的に対処します。

  • リモート状態管理とステートロックは、tfstateのコンフリクトを原理的に排除します。
  • モジュールとディレクトリベースの環境分離は、コードのコピペによるメンテナンス性の低下を防ぎ、DRYな構成を実現します。
  • 外部ストアによる機密情報管理は、安全なクレデンシャル管理の明確な答えとなります。
  • CI/CDパイプラインによるplanの自動化とapplyの統制は、形骸化したレビュープロセスを、再現可能で信頼性の高いデプロイメントワークフローへと昇華させます。

以下の表は、プロジェクトの成長フェーズに応じて、これらのプラクティスを段階的に導入していくためのロードマップです。

フェーズ推奨アーキテクチャ理由
MVP / 個人開発ローカルステート、単一ディレクトリ速度が最優先。まずは動くものを作ることが重要。
チーム開発開始 (2-5人)リモートステート (S3+DynamoDB)、モジュール化の開始状態のコンフリクトを防ぎ、チーム開発の基盤を築く。
事業成長期 (複数チーム)ディレクトリベースの環境分離CI/CD の完全自動化機密情報の外部管理環境分離によるリスク低減と、自動化によるデプロイ頻度の向上が求められる。
大規模運用terragrunt 等のラッパーツール導入、ポリシー・ガードレールの強制 (OPA)DRY 原則の徹底と、組織全体のガバナンスをコードで強制する段階。

次のステップ: IaCプラクティスの成熟

このロードマップの先には、さらに成熟したIaCプラクティスが存在します。

  • Policy as Code: Open Policy Agent (OPA) や HashiCorp Sentinel を CI/CD パイプラインに統合し、「特定のリージョン以外にリソースを作成させない」「必須のタグが付与されているか検証する」といった組織のガバナンスルールをコードで強制します。
  • コスト管理の自動化: infracost のようなツールを導入し、Pull Request 段階でインフラ変更がコストに与える影響を自動的に算出し、レビュープロセスに組み込みます。
  • テストの自動化: terratest を用いて、インフラモジュールが期待通りにリソースを作成し、設定されているかを検証する自動テストを実装します。

本稿で解説した原則は、あなたのプロジェクトを次のフェーズへと安全に導くための道標となるでしょう。まずは、あなたのチームが現在直面している最大の痛み(例えば、tfstate のコンフリクト)を特定し、それを解決するプラクティス(リモートバックエンド)から導入を始めてみてください。その一歩が、統治可能でスケーラブルなインフラへの道を開くはずです。

著者について

佐藤 裕介

佐藤 裕介

大規模サービスのインフラ運用経験10年以上。Kubernetes、Terraform、CI/CDパイプライン構築を得意とし、信頼性の高いシステム基盤を提供します。

サービスに関するお問い合わせ

開発・技術支援に関するご相談はお気軽にお問い合わせください。

お問い合わせ