マルチリージョンは「二重構成を作ること」ではなく「一貫した運用で意図した切替ができること」を指します。Terraformは構成の再現性を担保できますが、DR(災害対策)で求められるRTO/RPOを満たすには、プロバイダの設計、ステートの境界、並行実行の制御を意識した作り込みが必要です。
本稿では公式ドキュメントの挙動に基づき、Active-Active/Active-Passiveの選択軸、プロバイダのエイリアス、バックエンドの可用性・ロック、ワークスペースの位置づけ、そして試験で問われやすい落とし穴を整理します。
DR要件はRTO(復旧時間目標)とRPO(目標復旧時点)で定義します。Terraformはインフラ定義の再現性を提供しますが、RTO/RPO達成は状態管理(state)、依存関係、適用順序の設計次第です。Active-Activeはトラフィック配分やデータ整合性を重視し、Active-Passiveは切替手順の明確さとコストを重視します。
Terraformの役割は「同一の定義を複数リージョンに矛盾なく適用する」「並行適用で競合しないようにする」「状態を破損させない」です。DNS/トラフィックの切替はクラウドサービス側機能(例: グローバルDNS/トラフィックマネージャ)と合わせて運用計画に落とし込みます。
マルチリージョン適用フロー(概念図)
リージョン反復は「リージョンごとにモジュールを呼び出す」構成が最も読みやすく、安全です。プロバイダはfor_eachできないため、必要なリージョン分だけエイリアスを定義し、モジュールに渡します。モジュール側はデフォルトのaws(または対象クラウド)プロバイダを受け取り、同一のコードをリージョン別に適用します。
依存関係はモジュール入力/出力で明示し、暗黙のデータソース参照に頼らないのが安定します。並行適用時の競合はロックで防ぎつつ、相互参照は避けて「片方向の配線」に統制します。
エイリアス付きプロバイダとモジュールの呼び出し例(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バックエンドを使う場合は、サービス側のロック・キューイングと高可用性が前提になります。
| ステート管理単位 | メリット | リスク/注意 | 代表ユースケース |
|---|---|---|---|
| 単一ステートで両リージョンを一括管理 | 全体像が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で切替の原子性を高めます。
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
}
パイプラインは「リージョン単位のステージ」を基本とし、失敗時は後続ステージを止めます。Active-Passiveでは、先にスタンバイ側を最新化→健全性確認→トラフィック切替→プライマリ更新の順で進めると安全です。
計画(plan)と適用(apply)は、同一のリモートステート・同一バージョンのコードで行います。手元のplanを持ち回るのではなく、CI上で新鮮なplan→直後にapplyという流れに統一します。Terraform Cloud/Enterprise利用時はワークスペースごとのキューイングで同時実行を制御できます。
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)は一時的な回避策であり、恒常運用に使うと依存の破綻を招きます。依存はモジュール設計で解決するのが本筋です。
リージョン移行や命名変更時の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を考慮しつつ一貫性を高める設計として最も適切なのはどれか。
正解: A
リージョン分割ステートは障害波及とロールバックの制御に有利で、S3+DynamoDBロックにより整合性を担保できます。モジュールの二重適用は定義の再利用性を高め、remote stateの片方向参照で依存を明示できます。CIでリージョン逐次適用とすることで失敗時の影響を限定できます。他の選択肢は単一ステートでの大規模失敗、ロック無効化、ワークスペース乱用、-target依存といったアンチパターンを含みます。
S3バックエンドでクロスリージョンレプリケーション(CRR)を有効にすれば、DynamoDBロックも冗長化されますか?
いいえ。CRRはS3オブジェクト(stateファイル)の複製に関する機能で、DynamoDBのロックテーブルは別サービスかつリージョン単位です。ロックは特定リージョンのテーブルに対して行われるため、フェイルオーバ戦略とは別に「どのテーブルでロックするか」を決め、切替時の運用手順を定義してください。
ワークスペースでリージョンを切り替える設計はありですか?
非推奨です。ワークスペースは主に環境(dev/stg/prod)など論理的な切り分けに用い、リージョン差分はステート分割やモジュールの二重適用で扱うのが一般的です。ワークスペースでリージョンを切替えると依存関係や権限境界が曖昧になり、誤適用リスクが高まります。
両リージョンを同時にapplyしたいのですが、安全に行う方法はありますか?
原則は逐次実行です。どうしても並列化する場合でも、各リージョンは独立ステートとし、各ステートでのロックを有効化した上で、相互依存(remote state参照)が無いことを確認してください。相互参照がある場合は循環や部分失敗の原因になります。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける
Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...
Terraform Authoring & Ops Pro: 上位資格の範囲と対策
上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...
Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす
Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...
Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義
Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...
Terraform Data Source徹底理解:既存リソースの参照で壊さず足す
Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...