iT邦幫忙

2025 iThome 鐵人賽

DAY 13
1
DevOps

30 天 Terraform 學習筆記:從零開始的 IaC 實戰系列 第 13

Day 13 - Terraform Resource 關係管理:depends_on、implicit dependencies

  • 分享至 

  • xImage
  •  

在前面幾天,我們從概念著手了解了 Terraform 的運作方式、狀態檔、Remote State,再一步步練習實作,從建立 VM、設定 Provider、活用 Variables 與 Data Sources 到輸出 Outputs。
不過目前的這些練習大多是「單點操作」:一個 VM、一個 Bucket,或是查詢單一資源資訊。

而今天要談的 資源建立順序,就是把這些零散的元件「串起來」的最後一塊拼圖。因為在真實環境裡,資源往往不是孤立存在的,而是彼此有上下游依賴:VM 要依賴 VPC、CI/CD 要依賴 Bucket、Database 要在初始化前先啟動。

我們可以想像一下:

  • 在還沒建立 VPC,VM 就嘗試掛載網路
  • Bucket 還沒建立完成,CI/CD pipeline 就嘗試寫檔案
  • Database 還沒啟動,就有人跑初始化 SQL

這樣會發生什麼?結果是錯誤、重試、甚至 pipeline 卡住。

而 Terraform 提供了兩種方式來管理資源之間的關係:隱含依賴(implicit dependencies)顯式依賴(depends_on)

隱含依賴(Implicit Dependencies)

Terraform 很聰明,只要你在資源參數中引用了另一個資源的屬性,它就會自動知道兩者之間的依賴關係。

舉個例子:

resource "google_compute_network" "vpc" {
  name = "my-vpc"
}

resource "google_compute_instance" "vm" {
  name         = "my-vm"
  machine_type = "e2-micro"
  zone         = "asia-east1-b"

  network_interface {
    network = google_compute_network.vpc.name
  }
}

這裡 VM 需要用到 VPC 的名稱,Terraform 會自動判斷出:必須先建立 VPC,才能建立 VM
我們不需要寫任何 depends_on。因為大部分情況下,隱含依賴就足夠了!

顯式依賴(depends_on)

問題是有些時候「參數沒有引用到資源」,但實際上卻有依賴關係。
這時候 Terraform 就沒辦法自己推導,需要我們手動加上 depends_on

舉個例子:

resource "google_storage_bucket" "bucket" {
  name     = "my-app-bucket"
  location = "ASIA"
}

resource "null_resource" "notify" {
  provisioner "local-exec" {
    command = "echo 'Bucket 建立完成!'"
  }

  depends_on = [google_storage_bucket.bucket]
}

這裡的 null_resource 沒有直接用到 bucket.name,所以 Terraform 不會自動建立依賴關係
但我們邏輯上需要等 Bucket 建好,才去通知或做後續流程,因此必須手動加上 depends_on

常見應用場景

IAM 綁定

當我們幫資源加 IAM 權限時,Terraform 可能會同時執行「建立資源」和「設定 IAM」,導致 Race Condition。

resource "google_storage_bucket" "bucket" {
  name     = "my-app-bucket"
  location = "ASIA"
}

resource "google_storage_bucket_iam_binding" "binding" {
  bucket   = google_storage_bucket.bucket.name
  role     = "roles/storage.admin"
  members  = ["user:dev@example.com"]

  depends_on = [google_storage_bucket.bucket]

沒有 depends_on 可能會發生錯誤:「Bucket 還不存在,但 IAM 綁定已經在跑」。

Database 初始化

很多人第一次踩坑的地方就是 Cloud SQL 或 RDS

resource "null_resource" "init_db" {
  provisioner "local-exec" {
    command = "psql -h ${google_sql_database_instance.db.public_ip_address} -U root -d mydb -f init.sql"
  }

  depends_on = [google_sql_database_instance.db]
}

如果沒有加 depends_on,Terraform 可能會同時建立 DB instance 和跑初始化 SQL,結果就是:
「連不到 DB」→ pipeline 失敗。

CI/CD Pipeline 串接

團隊在 CI/CD 裡跑 Terraform 建立 GCS Bucket,然後立刻執行測試去上傳檔案。
結果 Terraform 還在建立 Bucket 的時候,測試就已經跑起來,當然會失敗。

解法就是:

  • 在 Terraform 裡面加 depends_on,確保測試資源在 Bucket 後才跑
  • 或者在 CI/CD Workflow 中,透過 terraform output 確認資源存在後再繼續

使用建議

整理幾點建議供大家參考:

  • 盡量靠隱含依賴,保持程式乾淨。
  • 只有在必要時才用 depends_on,避免造成過多「強制順序」,影響 Terraform 的平行化執行效能。
  • 在多人協作的專案中,建議在 README 或註解中寫清楚「為什麼需要 depends_on」。

總結一下

Terraform 的資源關係管理就是在確保:

  1. 隱含依賴(implicit dependencies):透過引用參數,Terraform 自動判斷順序
  2. 顯式依賴(depends_on):當參數沒有引用,但邏輯上需要順序,就要手動指定

實務上,80% 情況靠隱含依賴就夠了,但那 20% 沒處理好,往往就是 CI/CD pipeline 裡最難 debug 的「隱藏炸彈」。所以能掌握好這個觀念,就能避免資源建立的 Race Condition,讓 Terraform 配置更穩定、更可預期~

🐈🐈🐈

好啦~學到這裡 Terraform 的基礎操作就告一段落了,目前累積的這些能力已經足以在專案裡建立一些小型基礎設施。不過,當專案開始變大,或多人協作時,光靠這些單一檔案的寫法很快就會變得混亂。這時候就需要更進一步的技巧 —— 模組化(Modules)與專案架構設計。

所以!明天我們要進入 模組與架構篇 的實作練習,一起來看看如何把這些基礎能力組織成更有結構、可重複使用的 Terraform 專案~🤩


上一篇
Day 12 - Terraform Outputs:資訊擷取與串接
系列文
30 天 Terraform 學習筆記:從零開始的 IaC 實戰13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言