depends_on

更新时间:2025-03-21 03:10:58

本文档介绍了 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,可前往了解更多细节。
    AI助理

    点击开启售前

    在线咨询服务

    你好,我是AI助理

    可以解答问题、推荐解决方案等