Terraform

Terraformで実現するマルチリージョン設計: 災害対策と一貫性の両立

2026-04-19
NicheeLab編集部

マルチリージョンは「二重構成を作ること」ではなく「一貫した運用で意図した切替ができること」を指します。Terraformは構成の再現性を担保できますが、DR(災害対策)で求められるRTO/RPOを満たすには、プロバイダの設計、ステートの境界、並行実行の制御を意識した作り込みが必要です。

本稿では公式ドキュメントの挙動に基づき、Active-Active/Active-Passiveの選択軸、プロバイダのエイリアス、バックエンドの可用性・ロック、ワークスペースの位置づけ、そして試験で問われやすい落とし穴を整理します。

マルチリージョンとDRモデルの前提整理

DR要件はRTO(復旧時間目標)とRPO(目標復旧時点)で定義します。Terraformはインフラ定義の再現性を提供しますが、RTO/RPO達成は状態管理(state)、依存関係、適用順序の設計次第です。Active-Activeはトラフィック配分やデータ整合性を重視し、Active-Passiveは切替手順の明確さとコストを重視します。

Terraformの役割は「同一の定義を複数リージョンに矛盾なく適用する」「並行適用で競合しないようにする」「状態を破損させない」です。DNS/トラフィックの切替はクラウドサービス側機能(例: グローバルDNS/トラフィックマネージャ)と合わせて運用計画に落とし込みます。

  • DRパターン: Active-Active(低RTO/RPO、実装複雑)/ Active-Passive(中RTO/中〜高RPO、運用単純)
  • Terraformは「宣言→計画→適用」で一貫性を担保。計画と適用は同一のリモートステートで、ロック有効が前提
  • データレイヤ(DB、ストレージ)のレプリケーション/復旧はクラウドサービス側の機能を使用。Terraformは設定の宣言と配線に集中

マルチリージョン適用フロー(概念図)

state/lockoutputsDev/CI RunnerPlan/ApplyTerraform CLI/CloudPlan/Apply/LockRemote State BackendS3/Terraform Cloud/etc.Provider Region AProvider Region BResources AResources BS3バックエンド利用時はDynamoDBによるロックを併用。TFC/Enterpriseの場合はサービス側のロック/キューイング適用。

プロバイダのエイリアスとモジュール化パターン

リージョン反復は「リージョンごとにモジュールを呼び出す」構成が最も読みやすく、安全です。プロバイダはfor_eachできないため、必要なリージョン分だけエイリアスを定義し、モジュールに渡します。モジュール側はデフォルトのaws(または対象クラウド)プロバイダを受け取り、同一のコードをリージョン別に適用します。

依存関係はモジュール入力/出力で明示し、暗黙のデータソース参照に頼らないのが安定します。並行適用時の競合はロックで防ぎつつ、相互参照は避けて「片方向の配線」に統制します。

  • プロバイダはaliasでリージョン別に用意し、module providers引数で渡す
  • モジュールは「1リージョンを1インスタンス」で扱う。for_eachはモジュール側ではなく呼び出し側で使うと簡潔
  • モジュール間の依存は入力/出力で接続。dataソースによる相互依存は避ける

エイリアス付きプロバイダとモジュールの呼び出し例(AWSを例に概念を説明)

terraform {
  required_version  = ">= 1.5.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = ">= 5.0" }
  }
}

variable "regions" {
  # primary/secondaryを固定名で扱う。実務では環境毎の変数ファイルで値を切替
  type = object({
    primary   = object({ region = string })
    secondary = object({ region = string })
  })
}

provider "aws" {
  alias  = "primary"
  region = var.regions.primary.region
}

provider "aws" {
  alias  = "secondary"
  region = var.regions.secondary.region
}

# 1リージョン=1モジュールの原則。呼び出し側で2回呼ぶ
module "app_primary" {
  source    = "./modules/app"
  providers = { aws = aws.primary }
  region    = var.regions.primary.region
}

module "app_secondary" {
  source    = "./modules/app"
  providers = { aws = aws.secondary }
  region    = var.regions.secondary.region
}

# modules/app/main.tf(抜粋)
# module側はデフォルトawsプロバイダを受けるだけ
variable "region" { type = string }

resource "aws_s3_bucket" "logs" {
  bucket = "nicheelab-logs-${var.region}"
  tags   = { managed_by = "terraform", region = var.region }
}

ステート分割戦略とバックエンド可用性

ステートの境界は「障害の波及範囲(blast radius)」と「並行開発の独立性」で決めます。マルチリージョンでは、同一ステートで両リージョンを一括管理する方法と、リージョン別にステートを分ける方法のトレードオフを理解してください。一般に、リージョン障害時の影響分離とロールバック容易性を優先し、リージョンごとにステートを分ける設計が無難です。

リモートバックエンドではロックを必須にします。S3バックエンドはDynamoDBロックを併用し、バケットはバージョニングと暗号化を有効化します。クロスリージョンレプリケーションはバックアップとして有用ですが、DynamoDBロックテーブルはリージョン単位である点に注意が必要です。Terraform Cloud/Enterpriseのremoteバックエンドを使う場合は、サービス側のロック・キューイングと高可用性が前提になります。

  • backend設定は変数参照不可。-backend-configで環境/リージョンごとに注入
  • S3+DynamoDBロック: バージョニング、SSE、ブロックパブリックアクセス、適切なIAMを設定
  • Terraform Cloud/Enterprise: ワークスペース毎にキューイング・ロックが提供されるため並行実行の衝突を回避しやすい
ステート管理単位メリットリスク/注意代表ユースケース
単一ステートで両リージョンを一括管理全体像が1つのplan/applyに収まり依存可視性が高いplan/applyの失敗時に全体が巻き込まれる。並行作業が衝突しやすい小規模/学習環境。相互依存が強く同時更新が必須な構成
リージョン別ステート(推奨)障害の波及を分離。ロールバック容易。並行開発に強いクロスリージョン依存はremote state経由で明示配線が必要Active-PassiveやActive-Activeでの段階的更新
サービス×リージョンで更に細分化変更単位が極小。責務分離が明確ステート数が増え運用が複雑。依存管理の手間増大規模組織、チーム境界が明確なモノレポ/マルチレポ

S3バックエンドの部分設定とリージョン別適用例

# backendは変数参照不可。部分定義して起動時に注入
terraform {
  backend "s3" {}
}

# backend-us-east-1.hcl
bucket         = "tfstate-prod"
key            = "app/us-east-1/terraform.tfstate"
region         = "us-east-1"
dynamodb_table = "tf-locks-prod"
encrypt        = true

# backend-ap-northeast-1.hcl
bucket         = "tfstate-prod"
key            = "app/ap-northeast-1/terraform.tfstate"
region         = "ap-northeast-1"
dynamodb_table = "tf-locks-prod"
encrypt        = true

# 初期化と適用(リージョン単位で分けて実行)
terraform init -backend-config=backend-us-east-1.hcl
terraform apply -auto-approve

# 別ディレクトリ/別ワークスペースでap-northeast-1を同様に実行
terraform init -backend-config=backend-ap-northeast-1.hcl
terraform apply -auto-approve

一貫性の担保: ロック、依存、データ取得の作法

ロックは必須です。S3バックエンドならDynamoDBロック、Terraform Cloud/Enterpriseならワークスペースのロック/キューイングで同時実行を防ぎます。ロック待ち時間は-lock-timeoutで延長可能です。

依存は極力「入力/出力(module outputs)」でつなぎ、dataソースの過度な利用を避けます。remote stateデータソースは片方向に限定し、循環参照は作らないでください。計画の安定性のため、明確なdepends_onをモジュールで使うのは有効です。

ドリフト検出にはplanやrefresh-onlyの適用を活用します。破壊的変更が必要な場合はlifecycleのcreate_before_destroyやreplace_triggered_byで切替の原子性を高めます。

  • terraform plan -lock=true(デフォルト)/ -lock-timeout=5m などで競合回避
  • module間はoutputs→inputsの片方向で配線。remote stateは読み取り専用で使用
  • 破壊的変更が予期される箇所はcreate_before_destroyで先行作成→切替
  • 循環参照、-targetの乱用は計画の不整合を招くため避ける

remote stateで片方向に依存関係を配線する例

# us-east-1側のネットワーク出力を、ap-northeast-1側で参照(片方向)
# ap側のコード(抜粋)
data "terraform_remote_state" "primary_net" {
  backend = "s3"
  config = {
    bucket = "tfstate-prod"
    key    = "network/us-east-1/terraform.tfstate"
    region = "us-east-1"
  }
}

module "app_secondary" {
  source    = "./modules/app"
  providers = { aws = aws.secondary }
  region    = var.regions.secondary.region
  # 片方向に必要最小限の情報だけを受け取る
  vpc_id    = data.terraform_remote_state.primary_net.outputs.vpc_id
}

CI/CDと運用: 適用順序、フェイルオーバ、ロールバック

パイプラインは「リージョン単位のステージ」を基本とし、失敗時は後続ステージを止めます。Active-Passiveでは、先にスタンバイ側を最新化→健全性確認→トラフィック切替→プライマリ更新の順で進めると安全です。

計画(plan)と適用(apply)は、同一のリモートステート・同一バージョンのコードで行います。手元のplanを持ち回るのではなく、CI上で新鮮なplan→直後にapplyという流れに統一します。Terraform Cloud/Enterprise利用時はワークスペースごとのキューイングで同時実行を制御できます。

  • リージョンごとにジョブを分け、失敗時は次リージョンをスキップ
  • DNS/トラフィック切替は明示的な手順として別ジョブに分離(半適用を避ける)
  • Planは成果物化して短時間内に同一環境で即時Apply(差分の混入を防止)
  • バックエンド認証情報はOIDCや短期クレデンシャルでローテーションする

GitHub Actionsでリージョン別に逐次適用する雛形(概念)

jobs:
  apply-us:
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init -backend-config=backend-us-east-1.hcl
      - run: terraform plan -out=plan.out -lock-timeout=5m
      - run: terraform apply -auto-approve plan.out
  apply-ap:
    needs: apply-us
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init -backend-config=backend-ap-northeast-1.hcl
      - run: terraform plan -out=plan.out -lock-timeout=5m
      - run: terraform apply -auto-approve plan.out

試験で狙われやすいポイントと落とし穴

バックエンド設定は変数化できません。-backend-configで注入するか、環境ファイルを分けます。ワークスペースはリージョン分割のためではなく、基本は環境(dev/stg/prod)など論理的な切り分けに使います。

リソース名の変更やリージョン間のリソース移動時はmovedブロックで状態の移行を宣言し、不要な再作成を避けます。既存リソースの取り込みにはimportブロックまたはterraform importを用います。

ターゲット適用(-target)は一時的な回避策であり、恒常運用に使うと依存の破綻を招きます。依存はモジュール設計で解決するのが本筋です。

  • backendでは変数参照不可。-backend-configで対応
  • ワークスペース≠リージョン。リージョンはステート分割/モジュール複製で扱う
  • movedブロックでステートを安全に移行。importで既存資産を取り込み
  • -target乱用は不整合の温床。計画の完全性を重視

リージョン移行や命名変更時のmovedブロック例

terraform {
  required_version = ">= 1.5.0"
}

# 以前: aws_s3_bucket.primary
# 以後:  aws_s3_bucket.this
moved {
  from = aws_s3_bucket.primary
  to   = aws_s3_bucket.this
}

resource "aws_s3_bucket" "this" {
  bucket = "nicheelab-logs-us-east-1"
}

問題で確認

Pro

問題 1

本番ワークロードをus-east-1(プライマリ)とap-northeast-1(スタンバイ)で運用する。TerraformでDRを考慮しつつ一貫性を高める設計として最も適切なのはどれか。

  1. リージョンごとにステートを分割し(S3+DynamoDBロック)、同一モジュールをプロバイダエイリアスで二重適用。クロスリージョン依存はremote state出力を片方向に参照し、CIでリージョン単位に逐次plan/applyする。
  2. 単一ステートで両リージョンを一括適用し、失敗時は手動で不要差分を削除して再実行する。ワークスペースでリージョンを切り替える。
  3. 両リージョンのapplyを並列で実行し、ロックは無効化する。DRはS3のクロスリージョンレプリケーションに任せる。
  4. バックエンド設定を変数化してリージョンを切替える。dataソースで相互参照し、-targetで依存順序を都度調整する。

正解: A

リージョン分割ステートは障害波及とロールバックの制御に有利で、S3+DynamoDBロックにより整合性を担保できます。モジュールの二重適用は定義の再利用性を高め、remote stateの片方向参照で依存を明示できます。CIでリージョン逐次適用とすることで失敗時の影響を限定できます。他の選択肢は単一ステートでの大規模失敗、ロック無効化、ワークスペース乱用、-target依存といったアンチパターンを含みます。

よくある質問

S3バックエンドでクロスリージョンレプリケーション(CRR)を有効にすれば、DynamoDBロックも冗長化されますか?

いいえ。CRRはS3オブジェクト(stateファイル)の複製に関する機能で、DynamoDBのロックテーブルは別サービスかつリージョン単位です。ロックは特定リージョンのテーブルに対して行われるため、フェイルオーバ戦略とは別に「どのテーブルでロックするか」を決め、切替時の運用手順を定義してください。

ワークスペースでリージョンを切り替える設計はありですか?

非推奨です。ワークスペースは主に環境(dev/stg/prod)など論理的な切り分けに用い、リージョン差分はステート分割やモジュールの二重適用で扱うのが一般的です。ワークスペースでリージョンを切替えると依存関係や権限境界が曖昧になり、誤適用リスクが高まります。

両リージョンを同時にapplyしたいのですが、安全に行う方法はありますか?

原則は逐次実行です。どうしても並列化する場合でも、各リージョンは独立ステートとし、各ステートでのロックを有効化した上で、相互依存(remote state参照)が無いことを確認してください。相互参照がある場合は循環や部分失敗の原因になります。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Terraform

Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける

Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...

Terraform

Terraform Authoring & Ops Pro: 上位資格の範囲と対策

上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...

Terraform

Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす

Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...

Terraform

Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義

Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...

Terraform

Terraform Data Source徹底理解:既存リソースの参照で壊さず足す

Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...

Terraformの記事一覧 (102件)
© 2026 NicheeLab All rights reserved.