本文提供 Terraform 設定檔中資源之間依附元件的建議。
優先使用隱含依附元件,而非明確依附元件
當某項資源依附於其他資源的存在時,就會產生資源依附性。Terraform 必須能夠瞭解這些依附元件,確保資源以正確的順序建立。舉例來說,如果資源 A 依賴資源 B,系統會先建立資源 B,再建立資源 A。
您可以透過隱含和明確的依附元件宣告,建立 Terraform 設定依附元件。隱含依附元件會透過運算式參照宣告,而明確依附元件則會使用 depends_on
元數據引數指定。depends_on
引數會指定 Terraform 必須先完成資源或模組依附物件上的所有動作,才能繼續執行依附物件。
雖然兩種方法都能確保正確的作業順序,但隱含的依附元件通常會讓資源更新和替換的規劃更有效率。這是因為 Terraform 可以智慧地追蹤隱含依附元件中涉及的特定欄位,如果這些特定欄位在依附元件中保持不變,可能就不會變更依附元件。
相較於隱含依附性,明確依附性傳達的具體資訊較少。也就是說,如果 Terraform 不知道構成依附元件的特定屬性,就只能制定較保守的資源建立、更新和取代計畫。實際上,這會影響 Terraform 建立資源的順序,以及 Terraform 判斷資源是否需要更新或替換的方式。
建議您只在兩個資源之間的依附元件遭到隱藏,且無法透過隱含依附元件表示時,才使用 depends_on
中繼引數的明確依附元件。
在下列範例中,您必須先啟用必要的專案服務,才能建立 BigQuery 資料集。明確宣告此依附元件:
不建議使用:
module "project_services" {
source = "terraform-google-modules/project-factory/google//modules/project_services"
version = "~> 14.4"
project_id = var.project_id
activate_apis = [
"bigquery.googleapis.com",
"bigquerystorage.googleapis.com",
]
}
module "bigquery" {
source = "terraform-google-modules/bigquery/google"
version = "~> 5.4"
dataset_id = "demo_dataset"
dataset_name = "demo_dataset"
project_id = var.project_id
depends_on = [module.project_services] # <- explicit dependency
}
以下範例會將明確依附元件替換為隱含依附元件,方法是將 project_id
引數參照為 project_services
資源的 project_id
輸出屬性:
建議做法:
module "bigquery" {
source = "terraform-google-modules/bigquery/google"
version = "~> 5.4"
dataset_id = "demo_dataset"
dataset_name = "demo_dataset"
project_id = module.project_services.project_id # <- implicit dependency
}
使用隱含依附元件可讓您精確宣告依附元件,例如指定需要從上游物件收集的確切資訊。這麼做也可以減少在多個位置進行變更的需求,進而降低發生錯誤的風險。
參照從依附資源輸出的屬性
透過參照上游資源中的值來建立隱式依附元件時,請務必只參照輸出屬性,尤其是尚未知曉的值。這可確保 Terraform 在佈建目前資源前,先等待上游資源建立完成。
在以下範例中,google_storage_bucket_object
資源會參照 google_storage_bucket
資源的名稱引數。在 Terraform 規劃階段,引數會有已知的值。也就是說,當 Terraform 建立 google_storage_bucket_object
資源時,不會等待 google_storage_bucket
資源建立,因為參照已知的引數 (儲存桶名稱) 不會在 google_storage_bucket_object
和 google_storage_bucket
之間建立隱含的依附元件。這會破壞兩個資源之間隱含依附元件宣告的目的。
不建議使用:
# Cloud Storage bucket
resource "google_storage_bucket" "bucket" {
name = "demo-bucket"
location = "US"
}
resource "google_storage_bucket_object" "bucket_object" {
name = "demo-object"
source = "./test.txt"
bucket = google_storage_bucket.bucket.name # name is an input argument
}
google_storage_bucket_object
資源必須參照 google_storage_bucket_object
資源的 id
輸出屬性。由於 id
欄位是輸出屬性,因此只有在執行資源建立作業後,系統才會設定其值。因此,Terraform 會等待 google_storage_bucket_object
資源建立作業完成,再開始建立 google_storage_bucket_object
資源。
建議做法:
resource "google_storage_bucket_object" "bucket_object" {
name = "demo-object"
source = "./test.txt"
bucket = google_storage_bucket.bucket.id # id is an output attribute
}
有時沒有明顯的輸出屬性可供參考。舉例來說,請參考以下範例,其中 module_a
會將產生的檔案名稱做為輸入內容。在 module_a
中,檔案名稱會用於讀取檔案。如果您依原樣執行這段程式碼,就會收到 no such file or directory
例外狀況,這是因為 Terraform 在規劃階段嘗試讀取檔案,但檔案尚未建立。在這種情況下,檢查 local_file
資源的輸出屬性後,您會發現沒有明顯的欄位可用來取代檔案名稱輸入引數。
不建議使用:
resource "local_file" "generated_file" {
filename = "./generated_file.text"
content = templatefile("./template.tftpl", {
project_id = var.project_id
})
}
module "module_a" {
source = "./modules/module-a"
root_config_file_path = local_file.generated_file.filename
}
您可以引入明確的依附元件來解決這個問題。最佳做法是,請務必在註解中說明為何需要明確的依附元件:
建議做法:
module "module_a" {
source = "./modules/module-a"
root_config_file_path = local_file.generated_file.filename
depends_on = [local_file.generated_file] # waiting for generated_file to be created
}