本文档提供了有关表达 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
资源的 name 参数。参数已知
值。这意味着当 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
资源必须引用 id
output 属性。google_storage_bucket_object
自 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
}