depends_on
本文档介绍了 depends_on
的用法、使用场景、处理机制以及在阿里云环境中的具体示例
概述
depends_on
是 Terraform 中的一个元参数,用于明确声明资源或模块之间的依赖关系,处理 Terraform 无法自动推断的隐藏资源或模块依赖关系。
在 Terraform 的工作流程中,大多数依赖关系是通过隐式引用(一个资源的属性值使用另一个资源的属性)自动推断的,但有些依赖关系无法被 Terraform 自动检测。只有当资源或模块(Module) 依赖于另一个资源的行为,但在其参数中没有访问该资源的任何属性时,才需要显式指定依赖关系。例如,当一个资源的功能依赖于另一个资源或者模块的完整创建,但在代码中没有直接引用该资源或者模块时,就需要使用 depends_on
。
本文档介绍了 depends_on
的用法、使用场景、处理机制以及在阿里云环境中的具体示例。通过正确使用 depends_on
,可以确保资源按照预期顺序创建和销毁,避免由于依赖关系不明确而导致的部署问题。
使用须知
depends_on
元参数指示 Terraform 在执行声明依赖关系的对象的操作之前,完成依赖对象上的所有操作(包括读取操作)。当依赖对象是整个模块时,depends_on
会影响 Terraform 处理与该模块关联的所有资源和数据源的顺序。
应将 depends_on
作为最后的手段,因为它可能导致 Terraform 创建更保守的计划,替换比必要更多的资源。例如,由于不确定上游对象会发生什么变化,Terraform 可能会将更多值视为未知("known after apply")。当您为模块使用 depends_on
时,这种情况尤其可能发生。
我们建议在可能的情况下使用表达式引用来隐式表达依赖关系,而不是使用 depends_on
。表达式引用让 Terraform 了解引用来自哪个值,并且即使上游对象的其他部分有计划的更改,如果该特定值没有更改,也可以避免计划更改。
使用方法
您可以在Module块和所有资源块中使用 depends_on
元参数,无论资源类型如何。它需要对同一调用模块中的其他资源或子模块的引用列表。此列表不能包含任意表达式,因为 Terraform 需要在了解资源关系之前知道 depends_on
值,因此也必须在安全评估表达式之前知道。
我们建议始终包含一个注释,解释为什么使用 depends_on
是必要的。
资源间依赖示例
以下示例使用 depends_on
处理对 RAM 角色策略附加的"隐藏"依赖:
# 创建 RAM 角色
resource "alicloud_ram_role" "example" {
name = "terraform-example"
description = "Example role for demonstrating depends_on"
document = <<EOF
{
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": [
"ecs.aliyuncs.com"
]
}
}
],
"Version": "1"
}
EOF
}
# 附加系统策略到 RAM 角色
resource "alicloud_ram_role_policy_attachment" "system_policy" {
policy_name = "AliyunOSSReadOnlyAccess"
policy_type = "System"
role_name = alicloud_ram_role.example.name
}
# 创建自定义策略
resource "alicloud_ram_policy" "custom_policy" {
policy_name = "example-custom-policy"
description = "Custom policy for OSS access"
policy_document = <<EOF
{
"Statement": [
{
"Action": "oss:GetObject",
"Effect": "Allow",
"Resource": "acs:oss:*:*:example-bucket/*"
}
],
"Version": "1"
}
EOF
}
# 将自定义策略附加到角色
resource "alicloud_ram_role_policy_attachment" "custom_policy_attachment" {
policy_name = alicloud_ram_policy.custom_policy.name
policy_type = "Custom"
role_name = alicloud_ram_role.example.name
}
# 创建 ECS 实例
resource "alicloud_instance" "example" {
instance_name = "tf-example"
instance_type = "ecs.s6-c1m2.small"
image_id = "aliyun_2_1903_x64_20G_alibase_20230523.vhd"
vswitch_id = "vsw-abc123456"
# Terraform 可以从此推断实例与角色之间的依赖关系
role_name = alicloud_ram_role.example.name
# 然而,如果在此 ECS 实例中运行的软件需要特定的角色权限才能正常启动
# (例如,需要从 OSS 读取启动配置),那么还存在对策略附加的"隐藏"依赖关系,
# Terraform 无法自动推断,因此必须显式声明:
depends_on = [
alicloud_ram_role_policy_attachment.system_policy,
alicloud_ram_role_policy_attachment.custom_policy_attachment
]
}
模块间依赖示例
当一个模块的功能依赖于另一个模块的完整部署,但没有直接引用其输出时:
# 部署基础网络模块
module "network" {
source = "./modules/network"
vpc_cidr = "10.0.0.0/16"
# 其他参数...
}
# 部署安全组模块
module "security_groups" {
source = "./modules/security_groups"
vpc_id = module.network.vpc_id
# Terraform 可以推断此依赖,因为我们引用了网络模块的输出
}
# 部署应用模块
module "application" {
source = "./modules/application"
subnet_ids = module.network.subnet_ids
sg_id = module.security_groups.app_sg_id
# 如果应用部署需要等待特定的数据库初始化过程完成,
# 但没有直接引用数据库模块的任何输出,则需要显式依赖
depends_on = [
module.database
]
}
# 部署数据库模块
module "database" {
source = "./modules/database"
subnet_ids = module.network.database_subnet_ids
sg_id = module.security_groups.db_sg_id
}
通过明智地使用 depends_on
,您可以确保资源按正确的顺序创建,即使它们之间的依赖关系不明显。但请记住,始终优先使用直接引用来建立依赖关系,仅在真正需要时才使用 depends_on
。
注:本文参考自 Terraform 官方文档 depends_on,可前往了解更多细节。