Terraform

Terraform バージョンアップ戦略:破壊的変更への対応

2026-04-19
NicheeLab編集部

Terraform のアップグレードは、コア本体、各プロバイダ、モジュールの3層でそれぞれ破壊的変更が起こり得ます。影響を見極めるには、制約の設計、ロックファイルの運用、そしてステートの安全な移行手法が鍵になります。

この記事では、試験対策(Pro レベル相当)でも問われやすい原則を、実務でそのまま使える手順に落とし込みます。必要最小限の差分で検証し、可逆で安全に本番へ昇格するための具体策をまとめました。

基本方針とリスクモデル

破壊的変更は、Terraform コア、プロバイダ、モジュールのどこでも発生し得ますが、頻度と影響範囲は異なります。まずは層ごとにリスクを分離し、バージョン制約と検証の責務を明確化します。

実務および試験ともに重要なのは、required_version と required_providers による制約、.terraform.lock.hcl の活用、検証ブランチでの最小差分検証(init -upgrade の適用範囲を限定)です。

  • terraform ブロックの required_version で使用可能なコア範囲を固定する(例: ~> 1.6)。
  • required_providers で出所(source)と範囲(version)を明示し、プロバイダの MAJOR アップグレードは別ブランチで検証する。
  • モジュールは参照バージョンを固定し、内部のプロバイダ制約と競合しないことを確認する。
  • ロックファイル(.terraform.lock.hcl)は VCS にコミットし、差分をレビュー対象にする。
  • 検証環境で terraform init -upgrade を実行し、ロックファイルの変更と plan のノイズ量を評価する。
  • state のバックアップを取得し、移行が必要なら moved ブロックや terraform state mv を優先して破壊的置換を避ける。
対象推奨するバージョン制約例破壊的変更の兆候アップグレード時の要点
Terraform コア~> 1.6新しい型・メタ引数・挙動変更のアナウンス機能依存がなければ 1.x 内で保守的に追随。CI で plan 差分ゼロ確認。
プロバイダ~> 5.0(MAJOR 固定)属性の削除/非推奨化、デフォルト変更で置換が発生feature ブランチで init -upgrade、ロック差分レビュー、moved/state mv で置換回避。
モジュール~> 3.4入力/出力変数の変更、for_each/address 変更バージョン固定で段階的に更新。ラップ側で互換レイヤーを設ける。

推奨のバージョン制約例

terraform {
  required_version = "~> 1.6"
  required_providers = {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"   # MAJOR を固定し、MINOR/PATCH のみ許容
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.5"
    }
  }
}

module "network" {
  source  = "appcorp/network/aws"
  version = "~> 3.4"
  # ...
}

検証ブランチと環境昇格のワークフロー

アップグレードは、必ず検証ブランチでロックファイル差分と plan 差分を最小化して評価し、段階的に昇格させます。main ではロックファイルを書き換えない(readonly)運用が基本です。

CI では、計画と適用を分離し、ヒューマンゲートを設けます。ロックファイルの変更がある場合のみ reviewers を必須化するなど、差分駆動での審査を設計します。

  • feature/upgrade-<対象> ブランチを作成し、そこでのみ terraform init -upgrade を許可。
  • PR で .terraform.lock.hcl の差分と terraform plan の実行結果を必ず添付。
  • 一時スタック(ephemeral)またはステージングで apply して実デプロイ検証。
  • 問題なければ main にマージ。main の CI は -lockfile=readonly でロック不変を保証。
  • 本番 apply は plan ファイルを署名・保存し、再現可能な適用を行う。

アップグレード検証から本番昇格までの流れ

feature/upgradeinit -upgrade / lock diff reviewstaging (apply)real deploy test / rollback rehearsalproductioncontrolled apply (plan)

CI ジョブ例(差分最小の検証)

# 検証ブランチのみロック更新を許可
terraform init -upgrade
terraform validate
terraform plan -out=tfplan.bin

# ロックファイルと plan のアーティファクト化
sha256sum .terraform.lock.hcl > lock.sha256
terraform show -json tfplan.bin > tfplan.json

# main ではロック更新を拒否
# terraform init -lockfile=readonly

依存関係管理:ロックファイル、プロバイダ取得、ミラー

.terraform.lock.hcl は初回 init で作成され、プロバイダの厳密なバージョンとハッシュを固定します。アップグレード時は init -upgrade により候補が更新され、差分が明確化されます。ロックは必ず VCS にコミットし、レビュー対象にします。

オフラインや再現性のため、CLI 設定でプロバイダのミラーやキャッシュを使います。複数プラットフォームでビルドする場合は、terraform providers lock -platform で各プラットフォームのハッシュを追記します。

  • ロックをコミットしていないと、環境ごとに異なるプロバイダが入るリスクがある。
  • アップグレード検証は、必ずロック差分と plan 差分の双方を評価する。
  • CLI 設定ファイル(Unix: ~/.terraformrc, Windows: %APPDATA%/terraform.rc)で provider_installation を定義。
  • 社内アーティファクトリのミラーを優先し、direct をフォールバックに設定。
  • マルチプラットフォームの CI/CD では、terraform providers lock -platform=linux_amd64 -platform=darwin_arm64 などでハッシュを固定。

CLI 設定でのプロバイダミラー例 (~/.terraformrc)

provider_installation {
  filesystem_mirror {
    path    = "/opt/terraform-providers"
    include = ["registry.terraform.io/hashicorp/*"]
  }
  direct {}  # ミラーにない場合のみレジストリへ
}

State と論理移行:壊さずに名前や型を変える

リソース名の変更やアドレス体系の変更は、moved ブロックを使うことで破壊的置換を避けられます。コード上の rename を計画的に行い、plan で「1 to move」等の表示を確認してから適用します。

プロバイダの移行やソースアドレス変更では、terraform state replace-provider を用いて state を整合させます。どうしても計画に置換が出る場合でも、terraform state mv で単位を小さくし、影響を局所化します。

  • moved ブロックで論理リネームを宣言し、apply 時に state を安全に移す。
  • terraform state mv で個別の移行を実施(プランに不要な再作成が出る場合の救済)。
  • terraform plan -refresh-only を先に実行し、実リソースと state の乖離を解消してから本番計画に進む。
  • プロバイダ移行時は terraform state replace-provider で provider の出所を置換。

moved ブロックと state mv の併用例

terraform {
  required_version = "~> 1.6"
}

# 旧: resource "x_service_bucket" "main" → 新: resource "x_bucket" "primary"
moved {
  from = x_service_bucket.main
  to   = x_bucket.primary
}

# CLI での補助(どうしても移行が必要な場合)
# state のバックアップ
terraform state pull > state.backup.json
# アドレス変更
terraform state mv x_service_bucket.main x_bucket.primary
# プロバイダ出所の置換(例)
terraform state replace-provider registry.terraform.io/oldcorp/storage registry.terraform.io/newcorp/storage

安全なリリース手順とロールバック

アップグレードの適用は、再現可能性(plan の固定、ロックの固定)と可逆性(直前のバイナリ・ロック・state の保全)を確保して行います。apply 直前の drift 解消も安定化に有効です。

ロールバックは、直前に用いた Terraform バイナリとロックファイルをそのまま使用し、apply 前の state バックアップへ戻すのが最小リスクです。

  • 直前に terraform plan -refresh-only で乖離を解消し、ノイズのない plan を作る。
  • feature ブランチで init -upgrade、ロック差分レビュー、staging で apply。
  • main マージ後、本番は terraform init -lockfile=readonly を徹底。
  • 本番 plan はバイナリ化(-out)し、チェックサムとともに保管。
  • apply は保存済み plan を使用(再計算しない)。
  • state は apply 前後でバックアップを取得(pull して保管)。

本番ロールバックの最小手順(例)

# 事前
terraform version > TF_VERSION.txt
terraform state pull > state.pre.json
terraform plan -out=tfplan.bin
sha256sum tfplan.bin > tfplan.sha256

# 適用
terraform apply tfplan.bin

# ロールバック(必要時)
# 1) 直前に使った Terraform バイナリへ切替(tfenv など)
# 2) 直前の .terraform.lock.hcl を復元
# 3) state.pre.json を push
terraform state push state.pre.json

典型的な破壊的変更パターンと回避策

よくある破壊的変更は、属性のデフォルト値変更による置換、必須→任意(または逆)への型/検証の変更、名前変更による address 変更、for_each や count の式変更によるキーシフトなどです。検出と回避のため、計画の読み解きと lifecycle の使い分けが重要です。

置換が避けられない場合でも、create_before_destroy の適用で停止時間を抑制できます。逆に、安易な ignore_changes はドリフトの温床になるため、時間制限付きや根本対応までの暫定運用として明示的に扱います。

  • 名前変更は moved ブロックで宣言。for_each のキー変更は map にマイグレーション層を設けて段階的に。
  • デフォルト変更で置換が出る場合は、明示値を設定して差分を吸収。
  • プロバイダの breaking 変更は release note を読み、影響属性を明示的に設定して挙動を固定。
  • 停止時間が問題なら lifecycle.create_before_destroy を適用できるか確認(依存リソースの制約に注意)。
  • ignore_changes は限定的に。恒久対応後は削除してドリフトを解消。

置換を回避・制御する lifecycle 例

resource "example_resource" "svc" {
  name        = var.name
  immutable_a = var.immutable_a   # デフォルト変更が疑われる属性は明示値で固定
  mutable_b   = var.mutable_b

  lifecycle {
    create_before_destroy = true   # 可能な場合に適用して停止を抑制
    ignore_changes = [
      # 一時的なドリフト許容(恒久対応後に削除)
      mutable_b
    ]
  }
}

問題で確認

Pro

問題 1

プロバイダのメジャーバージョンを検証するために、できるだけ本番と同一の再現性を保ちつつ最小差分で影響を確認したい。最も適切な手順はどれか。

  1. feature ブランチで required_providers の範囲は変えずに terraform init -upgrade を実行し、.terraform.lock.hcl の差分をレビューしてから terraform plan -out を取得する
  2. main ブランチで required_version を外して最新の Terraform を直接 apply する
  3. ロックファイルを削除して本番環境で terraform init をやり直し、自動で選ばれたプロバイダで apply する
  4. terraform refresh だけを実行し、plan と apply は不要とする

正解: A

検証ブランチでのみ init -upgrade を行い、ロックファイル差分と plan をレビューするのが推奨です。main 直適用やロック削除は再現性が失われ、想定外の破壊的変更を招きます。refresh のみでは破壊的差分の有無を判断できません。

よくある質問

.terraform.lock.hcl はコミットすべきですか?複数プラットフォームをどう扱いますか?

はい、コミットすべきです。再現性の要であり、レビュー対象にもなります。異なる実行プラットフォームでの再現性を担保するには、検証ブランチで terraform providers lock -platform=<一覧> を実行して各プラットフォームのハッシュを追記してからマージします。

リソース名を変えたら置換が出そうです。破壊せずに移行できますか?

コードに moved ブロックを追加すれば、apply 時に state 上のアドレスを安全に移せます。より細粒度に制御したい場合は terraform state mv を併用します。どちらの方法でも、事前に plan で move が検出されていることを確認してください。

ロールバック時の注意点は?

直前に使用した Terraform バイナリと .terraform.lock.hcl をそのまま使い、apply 前に取得した state バックアップへ戻します。main では terraform init -lockfile=readonly を徹底し、意図しないロック更新を防いでください。

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

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の記事一覧 (101件)
© 2026 NicheeLab All rights reserved.