Terraform

Terraform lifecycle.replace_triggered_by徹底解説: 特定の変更で安全に再作成する設計と試験対策

2026-04-19
NicheeLab編集部

Terraform 1.2以降で追加されたlifecycle.replace_triggered_byは、他のリソースやモジュール出力の変化をトリガーに、対象リソースを明示的に置換(再作成)させるためのメタ引数です。通常は属性の差分に基づいて更新/置換が決まりますが、初期化時のみ参照される設定や、外部依存の安全性を担保したい場合に有効です。

この記事では、replace_triggered_byの正しい使い所と落とし穴、他機能との比較、試験で問われやすい観点、実務での検証パターンをまとめます。前提としてTerraform言語仕様とlifecycleの基本を把握している読者を想定します。

replace_triggered_byの基本と他機能比較

replace_triggered_byは、指定した参照(リソース全体やその属性、モジュール出力など)の値が変わった場合、当該リソースを更新ではなく置換として計画させます。これにより、プロバイダがインプレース更新をサポートしていても、意図的に作り直す設計が可能になります。

典型例は「初回作成時にのみ外部設定を取り込むコンポーネント」や「証明書・イメージのようにハッシュが変わったら確実に入れ替えたいリソース」です。参照先をリソース全体で指定すれば“そのリソースのいかなる差分でも”置換、属性で指定すれば“その属性値が変わったときのみ”置換が走ります。

  • 指定対象: リソース参照、リソース属性参照、モジュール出力の参照(いずれもPlan時に値変化を検出できるもの)。
  • 適用単位: 各リソースインスタンス(count/for_eachの各要素)に評価される。
  • 効果: 差分の有無に関わらず、トリガ参照の変化時は must be replaced としてPlanされる。
  • 注意: 依存順序はdepends_onの役割。replace_triggered_byは順序制御ではなく“置換の意図”を与える。
機能主目的トリガー対象/指定方法Planへの影響
lifecycle.replace_triggered_by特定の外部変化で置換を強制リソース/属性/モジュール出力参照指定参照が変化すると必ず置換(must be replaced)
depends_on作成/破棄の順序制御リソース/モジュール参照差分には影響せず、依存グラフのみ変更
null_resource.triggers値の変化でnull_resourceを再作成任意の値(文字列/マップ)null_resourceのみ再作成。他リソースには非適用
lifecycle.ignore_changes特定属性の差分を無視属性名(セット/リスト可)差分を抑止。置換/更新が計画されない(他要因の置換は別途発生し得る)

replace_triggered_byの依存と置換の流れ

module.caoutput: bundle_hashresource.kubernetes_secret.apilifecycle { replace_triggered_by = [module.ca...] }Plan時に "must be replaced"置換(新規作成 -> 旧リソース破棄)

基本パターン: モジュール出力や属性の変化で置換を強制する

# モジュール(例): 証明書バンドルのハッシュを出力
module "ca" {
  source = "./modules/ca"  # 実体は任意
  # ...
}

# 例1: モジュール出力でSecretを常に作り直す
resource "kubernetes_secret" "api" {
  metadata {
    name      = "api-secret"
    namespace = "default"
  }
  data = {
    # 実際の内容は別の引数で参照していてもOK
    ca_hash = module.ca.bundle_hash
  }
  lifecycle {
    replace_triggered_by = [
      module.ca.bundle_hash
    ]
  }
}

# 例2: リソース属性の変化で置換
resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.main.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = aws_acm_certificate.cert.arn

  default_action {
    type = "fixed-response"
    fixed_response {
      content_type = "text/plain"
      status_code  = 200
      message_body = "ok"
    }
  }

  lifecycle {
    replace_triggered_by = [
      aws_acm_certificate.cert.arn  # 証明書差し替え時はリスナーを置換
    ]
  }
}

Planでの評価順序とグラフ上の意味

replace_triggered_byは、Planの差分計算後に「トリガ参照の値が前回Stateから変わっているか」を確認し、該当すれば対象リソースに置換フラグを付与します。したがって、参照先がRefreshで更新されなければ変化として扱われません。

リソース全体を参照した場合は“当該インスタンスのいかなる計画変更でも”トリガ成立、属性参照であれば“その属性の値変化”に限定されます。count/for_eachの場合、各インスタンスで個別に評価されるため、変化があったインスタンスのみ置換されます。

  • Planは Refresh → Diff → Replace判定(置換要件集約) の順に近い流れで進む。
  • 参照先が同値(例: ハッシュ値不変)であれば置換は発生しない。
  • 参照先の粒度は可能な限り狭く(属性レベル)指定すると不要な置換を避けられる。
  • 依存順序はdepends_onで補完。replace_triggered_byのみでは作成順は保証されない。

for_eachと組み合わせた評価の最小化

# すべてのVMはベースイメージのダイジェストが変わったときだけ置換
locals {
  vms = {
    web  = { size = "small" }
    api  = { size = "medium" }
  }
}

module "base_image" {
  source = "./modules/base_image"
  # 出力: digest
}

resource "azurerm_linux_virtual_machine" "vm" {
  for_each = local.vms

  name                = "${each.key}-vm"
  resource_group_name = azurerm_resource_group.rg.name
  size                = each.value.size
  # ... 他の必須引数

  lifecycle {
    replace_triggered_by = [
      module.base_image.digest
    ]
  }
}

実務で効くパターン: 証明書・イメージ・初期化依存

証明書やイメージのように、値の“中身”が変わるが参照名は同一のケースでは、プロバイダがインプレース更新を行っても安全側に倒すため置換を明示することがあります。特に初期化スクリプトで外部リソースを一度だけ読み込む系は再作成が無難です。

また、コンテナ画像のダイジェスト変更時にDeploymentのローリングを強制したいが、providerの挙動や差分検出で取りこぼしがある環境では、replace_triggered_byで確実に入れ替える設計が有効です。

  • 証明書ローテーション: module.ca.bundle_hashを参照して対象コンポーネントを置換。
  • AMI/イメージ更新: module.image.digestを参照し、Nodeやインスタンスを再作成。
  • Init-only依存: 作成時のみ読み込む設定が変わる場合は置換で確実に反映。

コンテナ画像ダイジェストの変更でDeploymentを置換(例)

module "artifact" {
  source = "./modules/artifact"
  # output: image_digest
}

resource "kubernetes_deployment" "app" {
  metadata { name = "app" }
  spec {
    replicas = 3
    selector { match_labels = { app = "app" } }
    template {
      metadata { labels = { app = "app" } }
      spec {
        container {
          name  = "app"
          image = "example.com/app@${module.artifact.image_digest}"
        }
      }
    }
  }
  lifecycle {
    replace_triggered_by = [
      module.artifact.image_digest
    ]
  }
}

落とし穴とアンチパターン: 不要な置換・無限ループの回避

replace_triggered_byの指定が粗すぎると、ほぼ毎回置換されPlanが巨大化します。逆に細かすぎると期待どおり置換されません。参照粒度の設計が肝心です。また、時間ベースや乱数値のように“意図せず値が更新される”ものを参照すると、意図しない置換ループになります。

ignore_changesと併用する場合、ignore_changesで差分を無視していても、replace_triggered_byが成立すれば置換は発生します。差分抑制より“置換の意図”が優先される点に注意してください。

  • 粗い参照(リソース全体)は最小限に。できれば属性で限定する。
  • 周期的に変化する値(time_rotatingなど)をトリガにしない。
  • デバッグ時は対象インスタンスだけに絞って検証(選択的Plan)。
  • ignore_changesの指定だけでは置換の強制は避けられない設計にする。

アンチパターン例: 周期的な値を参照してしまう

# 悪い例: time_rotatingは一定間隔で値が変わるため、定期的に置換が走る
resource "time_rotating" "weekly" {
  rotation_days = 7
}

resource "some_resource" "target" {
  # ...
  lifecycle {
    replace_triggered_by = [
      time_rotating.weekly.id  # 値がローテーションするたび置換されてしまう
    ]
  }
}

null_resource.triggersからの移行: 意図の明確化と保守性向上

従来、外部値の変化に伴う再作成はnull_resourceのtriggersで代替することが多く、これに依存する別リソースの再適用を狙う設計が散見されました。しかし、この方法は意図が間接的で、依存グラフも読みにくくなります。

replace_triggered_byへ移行すると、“どの値の変化でどのリソースを置換するか”がコード上で直に表現でき、Planも読みやすくなります。順序制御が必要ならdepends_onを併用します。

  • triggersでの擬似トリガより、対象リソース自身に置換意図を記述する方が明快。
  • 移行時は: 1) triggersに相当する値を洗い出し 2) 対象リソースへreplace_triggered_byとして移設 3) 依存はdepends_onへ整理。
  • Planを比較し、不要な置換が増えていないかを確認。

移行例: null_resourceのtriggersからlifecycle.replace_triggered_byへ

# 旧: null_resourceを疑似トリガに利用
resource "null_resource" "trigger" {
  triggers = {
    ca_hash = module.ca.bundle_hash
  }
}

# 旧: 実リソースはtriggerに依存
resource "kubernetes_secret" "api" {
  # ...
  depends_on = [null_resource.trigger]
}

# 新: 実リソース自身にトリガを集約
resource "kubernetes_secret" "api" {
  # ...
  lifecycle {
    replace_triggered_by = [module.ca.bundle_hash]
  }
  # 順序が要るならdepends_onを追加
  # depends_on = [module.ca]
}

試験対策チェックリストと検証手順

試験では、replace_triggered_byとdepends_on/ignore_changesの違い、リソース参照と属性参照の粒度、count/for_each時の評価単位が問われやすいです。null_resource.triggersとの比較も頻出です。

実務検証は、小さなサンプルで“参照が変わる/変わらない”の両方を試し、Plan出力にmust be replacedが現れることを確認します。RefreshOnlyでの挙動確認も有効です。

  • replace_triggered_byは順序制御ではない(置換の意図)。
  • 属性レベルで参照し、不要な置換を抑制する設計がベストプラクティス。
  • count/for_eachは各インスタンスごとに評価される。
  • ignore_changesでは置換強制を打ち消せない点に注意。

手元検証コマンド例

# 初回
terraform init
terraform plan -out=tfplan
terraform apply tfplan

# 参照値を更新(例: module出力を変化させるコミット/バージョン変更)

# 置換の発生を確認
terraform plan | grep -A2 "must be replaced" || true

# 差分がなくなることの確認
terraform plan -refresh-only

問題で確認

Pro

問題 1

モジュールmodule.caが証明書バンドルのハッシュ(bundle_hash)を出力しており、kubernetes_secret.apiはこの値が変わったときに必ず作り直したい。正しいTerraform構成はどれか。

  1. kubernetes_secret.api の lifecycle に replace_triggered_by = [module.ca.bundle_hash] を指定する
  2. kubernetes_secret.api の depends_on に module.ca.bundle_hash を指定する
  3. null_resource を作成し triggers に module.ca.bundle_hash を設定し、kubernetes_secret.api をそれに depends_on させる
  4. kubernetes_secret.api の lifecycle に ignore_changes = [data] を指定する

正解: A

置換の意図を直接表現するにはlifecycle.replace_triggered_byが正解。depends_onは順序のみで置換は強制しない。null_resource+triggersは間接的かつ冗長。ignore_changesは差分を無視するだけで置換を強制しない。

よくある質問

replace_triggered_byに指定できるのは何ですか?変数やデータソースも使えますか?

主にリソース参照、リソース属性参照、モジュール出力など、Plan時に値変化を検出できる参照が対象です。変数のような静的値だけを指定しても“外部の変化”としては扱いにくく、設計上の明確さも損ないます。実務ではリソース/属性/モジュール出力に限定して設計するのが安全です。

ignore_changesと併用した場合、どちらが優先されますか?

ignore_changesは特定属性の差分を無視しますが、replace_triggered_byが成立するとリソースは置換されます。つまり、差分抑制より“置換の意図”が優先されると考えてください。

参照先がドリフトしたときも置換されますか?

PlanのRefreshで参照先の現在値がStateに反映され、その結果として“値が変わった”と認識できれば置換が計画されます。裏を返せば、参照先の変化をPlanが検出できない限り、置換は発生しません。定期的なplan/refreshと監視が重要です。

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

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.