Terraformは式中の参照から依存関係グラフを自動で構築しますが、参照が発生しない関係やプロバイダの整合性遅延を扱うときは、depends_onで明示的に順序を固定するのが安全です。
本稿はAssociateレベルの受験者と現場エンジニアを想定し、depends_onの基本・構文・ユースケース・アンチパターン・検証方法をまとめます。バージョン差異に敏感な箇所は注意書きも添えています。
Terraformはリソース間の属性参照(例: subnet.vpc_id = aws_vpc.main.id)を検出し、暗黙的な依存を自動で張ります。これが最優先の設計原則です。
しかし、参照を伴わない順序づけ(例: 監査ログバケットが先に存在していてほしい、IAM伝播待ちなど)は暗黙依存だけでは表現できないため、depends_onを使って明示的に順序を固定します。depends_onは作成時は依存先→依存元の順、破棄時は逆順で動作します。
| 観点 | 暗黙的依存関係 | 明示的依存関係 (depends_on) | 代表例 |
|---|---|---|---|
| 生成方法 | 属性参照から自動推論 | meta-argumentで手動指定 | subnetがvpc.idを参照 / バケット生成後に別監査設定 |
| 可読性 | コードが素直で読みやすい | 意図が明確だが多用は読みにくい | 暗黙が基本・不足分のみ明示 |
| 適用範囲 | 参照がある範囲に限定 | 参照が無くても任意に張れる | 監査用S3→他リソース全般など |
| 破棄順序 | 参照の逆順で自動決定 | 依存エッジを逆転して適用 | A depends_on Bなら破棄はA→B |
暗黙 vs 明示の依存関係(概念図)
暗黙的依存(属性参照)
[aws_vpc.main] ---> [aws_subnet.app]
^ |
| (vpc_id参照) | (subnet_id参照)
| v
[aws_internet_gateway.gw]-->[aws_route_table.rt]
明示的依存(depends_on)
[aws_s3_bucket.audit] --(depends_on)--> [null_resource.bootstrap]
(参照なしでも順序を固定)基本構文(resource・module・data)
resource "aws_s3_bucket" "audit" {
bucket = "org-audit-logs"
}
resource "aws_s3_bucket" "app" {
bucket = "app-bucket"
depends_on = [aws_s3_bucket.audit] # 参照しないが順序を固定
}
module "network" {
source = "./modules/network"
}
module "eks" {
source = "./modules/eks"
depends_on = [module.network] # モジュール間の順序固定
}
data "aws_iam_policy" "example" {
arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
# Terraformのバージョンによってはdepends_onがdataでも使える。必要時のみ慎重に。
depends_on = [aws_s3_bucket.audit]
}depends_onはリソースブロック、モジュールブロック(Terraform 0.13以降)で安定利用できます。データソースへの適用はバージョンによって差異があるため、必要時のみ検討し、まずは属性参照で依存を表現するのが原則です。
depends_onに列挙するのは他のリソースやモジュールの参照です。可変な計算式で動的に依存先を切り替えるような使い方は避け、誰が見ても固定の順序が読み取れる形に保ちます。
正と誤の例(読みやすい順序指定)
# 悪い例: 動的に依存先を切り替え(可読性が落ちる)
# resource "aws_s3_bucket" "app" {
# bucket = "app-bucket"
# depends_on = var.use_audit ? [aws_s3_bucket.audit] : []
# }
# 良い例: 監査バケットが必須なら常に固定で明示
resource "aws_s3_bucket" "app" {
bucket = "app-bucket"
depends_on = [aws_s3_bucket.audit]
}
# モジュール間
module "db" {
source = "./modules/db"
}
module "api" {
source = "./modules/api"
depends_on = [module.db]
}count や for_each を使うリソースにも、ブロックに1度書いた depends_on は全インスタンスに適用されます。インスタンスごとに別のdepends_onを付けることは基本的にできないため、設計段階で順序要件を揃えるか、依存を表す属性参照で分解するのが安全です。
for_eachのキーに応じて順序を変える必要がある場合は、上流のデータ構造や生成順序の設計を見直します。無理にdepends_onで辻褄合わせをすると循環や過度な直列化を招きやすく、plan/apply時間が伸びます。
for_each と depends_on の挙動
resource "aws_s3_bucket" "logs" {
bucket = "shared-logs"
}
# 全アプリバケットはshared-logsの後に作りたい
resource "aws_s3_bucket" "app" {
for_each = toset(["a", "b", "c"])
bucket = "app-${each.key}"
depends_on = [aws_s3_bucket.logs] # 3つ全てに適用
}
# 個別順序を変える設計は避け、必要なら属性参照で関係を作るユースケース: 参照が無いが順序を固定したい場面。例として、監査ログ用のS3バケットを最初に作成し、以降のサービスバケットは常にその後に作る、ネットワーク基盤(VPC/サブネット/ルート)を先に構築してからEKS/ECSを作る、といった方針です。
アンチパターン: プロバイダの一時的不整合(例: IAMの伝播遅延)を全てdepends_onで覆うこと。まずはリトライ・タイムアウト等の公式機構や適切な属性参照で解決し、やむを得ない場合だけピンポイントにdepends_onを使います。
IAMの伝播待ちに対する慎重な適用例
resource "aws_iam_role" "app" {
name = "app-role"
assume_role_policy = data.aws_iam_policy_document.assume.json
}
resource "aws_iam_role_policy_attachment" "readonly" {
role = aws_iam_role.app.name
policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
# EKSなど後段がIAMに依存するが、まずは属性参照/公式のリトライで様子を見る
module "eks" {
source = "./modules/eks"
depends_on = [aws_iam_role_policy_attachment.readonly] # 必要なときだけ付ける
}terraform graphでDOTを出力し、暗黙・明示の依存を俯瞰できます。過度な直列化や循環の予兆を早期に発見し、構造を直します。
狙い撃ちの-targetは便利ですが、依存グラフの整合を壊しやすいため恒常運用には不向きです。試験でも乱用は非推奨の知識として問われがちです。
graph/planの活用例
# 依存グラフの可視化
$ terraform graph > graph.dot
$ dot -Tpng graph.dot -o graph.png
# 特定モジュールのみ検証(恒常運用は非推奨)
$ terraform plan -target=module.eks暗黙依存が作れるならdepends_onは不要、という原則をまず押さえます。そのうえで、参照が発生しないが順序を固定したいケースでdepends_onを使う設問が典型です。
destroyの順序反転、moduleブロックでのdepends_onサポート、count/for_eachへの一括適用、-target乱用のリスクなどが頻出論点です。
誤答と正答のイメージ
# 誤: 参照があるのにdepends_onを多用
resource "aws_subnet" "app" {
vpc_id = aws_vpc.main.id # これで十分に依存が張られる
cidr_block = "10.0.1.0/24"
# depends_on = [aws_vpc.main] # 不要
}
# 正: 参照が無い順序だけ固定
resource "aws_s3_bucket" "audit" { bucket = "audit" }
resource "aws_s3_bucket" "app" {
bucket = "app"
depends_on = [aws_s3_bucket.audit]
}Associate
問題 1
チームは監査ログ用S3バケットを最初に作成し、その後にアプリケーション用バケットを作成したい。アプリケーション用バケットは監査バケットを参照しない。Terraformの推奨アプローチはどれか。
正解: A
参照が無いが順序を固定したいケースは、depends_onで明示的に依存を張るのが正解。sleepや手動適用は非推奨、不要な擬似参照の導入も避ける。
dataブロックでもdepends_onは使えますか?
Terraformのバージョンによって取り扱いが異なるため、まずは属性参照で依存を表現することを優先してください。どうしても取得順序を固定したい場合に限り、対応バージョンでdepends_onを検討します。
depends_onはdestroy(削除)時にも影響しますか?
はい。A depends_on Bであれば作成はB→A、削除はA→Bとなります。破棄順序の把握は運用上重要です。
count/for_eachの各インスタンスごとに別のdepends_onを設定できますか?
基本的にできません。ブロックに記載したdepends_onは全インスタンスに適用されます。個別の順序が必要なら設計を見直し、属性参照で依存を表現する方法を検討してください。
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を用いた既存リソース参照の基本、選択基準、評価順序、...