资源依赖

更新时间:

本文将介绍资源依赖关系。

在构建基础设施时,您可能希望有一个可视化的依赖图来表示基础设施架构,进而了解您的基础设施是如何连接和相互依赖的。

Terraform 在执行时,会从你的配置文件中自动构建依赖图,进而生成执行计划并刷新状态。例如一个创建 ECS 的配置文件:

provider "alicloud" {
  # 配置你的阿里云凭据和地域信息
  # 配置你的阿里云凭据,出于安全考虑,建议不要在这个文件中直接包含你的阿里云AccessKey和SecretKey,推荐使用环境变量或其它安全方式设置凭据:
  # export ALICLOUD_ACCESS_KEY="<你的阿里云Access Key>"
  # export ALICLOUD_SECRET_KEY="<你的阿里云Secret Key>"
  region = "cn-hangzhou"
}

# 创建 VPC
resource "alicloud_vpc" "my_vpc" {
  vpc_name   = "main-vpc"
  cidr_block = "10.0.0.0/16"
}

# 创建 VSwitch
resource "alicloud_vswitch" "my_vswitch" {
  vpc_id       = alicloud_vpc.my_vpc.id
  cidr_block   = "10.0.1.0/24"
  zone_id      = "cn-hangzhou-h"
  vswitch_name = "main-vswitch"
}

# 创建安全组
resource "alicloud_security_group" "my_sg" {
  vpc_id = alicloud_vpc.my_vpc.id
  name   = "main-security-group"
}

# 配置安全组规则允许 SSH 访问
resource "alicloud_security_group_rule" "allow_ssh" {
  type              = "ingress"
  ip_protocol       = "tcp"
  nic_type          = "intranet"
  policy            = "accept"
  port_range        = "22/22"
  priority          = 1
  security_group_id = alicloud_security_group.my_sg.id
  cidr_ip           = "0.0.0.0/0"
}

# 创建 ECS 实例
resource "alicloud_instance" "my_instance" {
  instance_name              = "Ubuntu20-Instance"
  image_id                   = "ubuntu_20_04_x64_20G_alibase_20240508.vhd" # Ubuntu 20.04 的镜像 ID
  instance_type              = "ecs.c6.large"                              # 2核4G
  security_groups            = [alicloud_security_group.my_sg.id]
  vswitch_id                 = alicloud_vswitch.my_vswitch.id
  internet_charge_type       = "PayByTraffic"
  instance_charge_type       = "PostPaid"
  system_disk_category       = "cloud_efficiency"
  password                   = "Abc@12345" # 设置登录密码
  internet_max_bandwidth_out = 10          # 设置带宽大于 0,自动分配公网 IP

  tags = {
    Name = "ubuntu20"
  }
}

ECS 实例的创建同时依赖于安全组和 VSwitch 的创建,依赖关系的建立是通过属性值 security_groups 和 vswitch_id 的赋值来建立依赖关系,Terraform 在执行时通过创建依赖图来确定资源操作的正确顺序。在有多个资源的复杂情况下,对于不存在依赖关系的资源,Terraform 将并行执行操作。

依赖关系

Terraform 有两种依赖关系:隐式依赖(Implicit Dependence)和显式依赖(Explicit Dependence)。隐式依赖是 Terraform 已知的,而显式依赖是未知的。

隐式依赖(Implicit Dependence)

当一个资源的创建依赖于另一个资源创建后的信息时,需要用到隐式依赖来让 Terraform 知晓依赖关系。

在这个示例中,VSwitch 和安全组的创建依赖于 VPC;ECS 实例的创建依赖于 VSwtich 和安全组;安全组规则的创建依赖于安全组,这些依赖关系是隐式的。

针对隐式依赖关系,Terraform 通过属性值引用赋值的方式来知晓。

image (21).png

例如,instance 的 vswitch_id 参数值是对 my_vswitch 资源的引用,进而建立了 instance 资源对 vswitch 资源的隐式依赖关系。

针对隐式依赖关系,Terraform 能够推断出依赖关系并根据这些依赖关系知道不同资源创建的顺序,进而确保配置文件中定义的所有资源都能按照这个顺序创建成功。

在这个例子中,资源之间的依赖关系和创建顺序正如下图所示:

graph.svg

当 Terraform 读取配置时,它将首先确保 vpc my_vpc 在 vswtich my_vswitch 和安全组 my_sg 之前创建,同时也会确保在 ECS 实例 my_instance 会在 my_vswitch 和 my_sg 之后完成创建。然后,将所有资源的属性保存在状态文件中,并将 my_vswitch 和 my_sg 中的 vpc_id 参数设置为 my_vpc 的 id 的值,将 my_instance 的 vswitch_id 和 security_groups 的值设置为 my_vswitch 和 my_sg 的值。

显示依赖(Explicit Dependence)

有时,某个资源只能在另一个资源创建后才能创建,在这种情况下,你需要显式地引入依赖关系,该依赖关系配置在 Terraform 配置代码内部,对 Terraform 不可见。在这种情况下,你可以使用 depends_on 来显式声明依赖关系。

depends_on 参数给你更多的灵活性来控制 Terraform 在配置中处理资源的顺序。无论资源类型是什么,depends_on 可以在模块内使用,该值可以是指向资源的表达式。

例如,假设你需要在上述例子的基础上再增加两个端口 443 和 8080 的访问规则,并希望 8080 端口规则在 443 端口规则创建成功之后才创建。这种依赖关系对 Terraform 不可见,必须显式提及。你可以使用 depends_on 显式声明 8080 端口规则对 443 端口规则的依赖:

image (22).png

在通过表达式赋值时,Terraform 将处理元参数 depends_on 中指定的资源,并确保在创建 8080 访问规则之前先创建 443 访问规则。在执行 terraform apply 后,你将注意到 8080 访问规则是在 443 访问规则之后创建的。

graph (1).svg

最后,我们需要注意的是,资源定义的顺序并不会影响 Terraform 执行的方式,因此你可以按照对你和你的团队最有意义的方式来组织配置文件。