【テクニカル・上級編】Terraformのdepends_onアンチパターン:なぜ依存関係の明示はコードの保守性を下げるのか – インフラ構成管理(IaC)活用バイブル

Terraformにおける`depends_on`の亡霊:依存関係の明示が招く「保守性の死」と、真の疎結合アーキテクチャ

Terraformのコードレビューをしていると、必ずと言っていいほど遭遇するのが `depends_on` の濫用だ。

「このリソースはあのアカウントの準備が終わってから作成すべきだ」
「APIの制限があるから、順番を強制したい」

一見、論理的に見えるその記述は、実はTerraformのグラフ理論に基づく最適化能力を自ら殺し、コードの保守性を奈落の底へ突き落とすアンチパターンである。本稿では、なぜ `depends_on` が「技術的負債の増殖装置」となるのか、そして、それを排除し、リソースの暗黙的な紐付けを極限まで活用した「真にスケーラブルなIaC」の設計論を説く。

—

1. `depends_on` が引き起こす「破滅の連鎖」

Terraformの核心は、リソース間の依存関係を静的解析し、依存のないリソースを並列実行してデプロイ速度を最大化する点にある。`depends_on` を明示するということは、「Terraformの賢明な並列化アルゴリズムを無視し、直列実行を強制する」という宣言に他ならない。

なぜこれが「毒」なのか?

1. スケーラビリティの崩壊: 小規模な環境では問題にならないが、数百のリソースを扱う大規模環境で `depends_on` を多用すると、デプロイ時間が数分単位で増大する。
2. リサイクル(破棄・再作成)の呪い: 特定のリソースに過剰な依存を持たせると、そのリソースのわずかな変更が、依存ツリー全体を巻き込む「再作成のドミノ倒し」を誘発する。
3. コードの可読性喪失: 依存関係がコードのあちこちに散らばり、「なぜこの順序でなければならないのか」というコンテキストがコードから消失する。

—

2. 「暗黙的な依存関係」という至高の設計

Terraformは、`output` や `reference`(例: `aws_instance.web.id`)を通じて、リソース間の依存関係を完全かつ自動的に把握している。

アンチパターン:明示的依存

悪手:依存関係をハードコードで強制している
resource “aws_security_group” “web” {
depends_on = [aws_vpc.main]
name = “web-sg”
}

ベストプラクティス:参照による依存解決

善手:VPCのIDを参照することで、Terraformは自動的に依存を検知する
resource “aws_security_group” “web” {
vpc_id = aws_vpc.main.id # ここで暗黙的な依存が確立される
name = “web-sg”
}

この「参照による依存」こそが、Terraformのグラフ構築の根幹だ。もし、参照関係にないリソース同士を順番に処理したいのであれば、それは設計自体が疎結合になっていない証拠である。

—

3. 依存関係の「リファクタリング」:極限の知見

それでも「どうしても順序を制御しなければならないケース」はある。だが、その場合も `depends_on` を使う前に、以下のアーキテクチャを検討せよ。

手法A:モジュールのカプセル化(疎結合化)

リソース同士を強引に紐付けるのではなく、モジュール境界を適切に設計する。`output` を介して必要な値だけを渡し、制御フローを親モジュールで管理する。これにより、個別のリソースへの `depends_on` を排除できる。

手法B:データソースによる動的解決

リソース構築と設定適用を分離する。インフラ基盤の構築と、その上のソフトウェア設定を別のTerraformプロジェクト(またはWorkspaces)に分割する。`terraform_remote_state` を活用し、依存関係を「状態」として受け渡すことで、物理的な依存を論理的に切り離す。

—

4. 現場で震えるほど役立つ「最適化ハック」

真のエキスパートは、Terraformの内部動作すらもハックする。

APIの制限に対する「待ち」の戦略

APIのレートリミットや伝播遅延で依存エラーが出るなら、`depends_on` で解決しようとするな。それは設計の敗北だ。代わりに、リソースの `lifecycle { create_before_destroy = true }` を適切に設定するか、あるいは `null_resource` や `local-exec` を使った「ヘルスチェック」を挟め。

伝播遅延を待つための賢いアプローチ
resource “null_resource” “wait_for_api” {
provisioner “local-exec” {
# APIが準備完了するまでポーリングするスクリプト
command = “until aws apigateway get-rest-api –rest-api-id ${var.api_id}; do sleep 5; done”
}
}

メモリ消費とプラン速度の最適化

大規模環境で `terraform plan` が遅い場合、それはグラフの複雑さが原因だ。

  • モジュール化の深度: 深すぎるネストは解析コストを増大させる。平坦化を推奨する。
  • 不要なデータソースの排除: 毎回APIを叩く `data` リソースは、実行時間を増大させる。頻繁に更新されない値は `tfvars` や `SSM Parameter Store` で管理し、固定値として扱う。

—

伝説的エンジニアからの提言

`depends_on` は、あくまで「最後の手段」である。
コードが複雑になったとき、安易に `depends_on` に逃げるのは、インフラの設計図をメンテナンス不能なスパゲッティコードに作り変えることと同義だ。

優れたIaCは、コードを読んだだけで「データフロー」が自然と頭に浮かぶ。リソース同士がどう繋がり、どう流れるか。その依存関係を「暗黙的な参照」に委ねることこそが、Terraformという強力なエンジンを最大限に駆動させる唯一の道である。

さあ、その `depends_on` を削除し、真の疎結合アーキテクチャへとリファクタリングを始めよう。それが、世界最高峰のインフラを目指す我々の責務だ。

タイトルとURLをコピーしました