4. 资源生命周期与依赖管理
Terraform 的核心价值不只是“把资源写出来”,而是让资源之间的创建、更新、销毁顺序可预测、可复现。要做到这一点,必须理解依赖关系如何被 Terraform 推导、如何被人工干预,以及生命周期元参数如何改变默认行为。本节围绕依赖图、生命周期参数和漂移处理三条主线展开。
一、依赖关系:隐式依赖与显式 depends_on
Terraform 在执行 plan 和 apply 时,会先把配置解析成一张有向无环图(DAG)。图中的节点是资源、数据源、模块和 provider,边表示“谁依赖谁”。依赖关系决定了操作顺序:被依赖者先创建,依赖者后创建;销毁时顺序相反。
隐式依赖来自表达式引用。只要一个资源在参数中引用了另一个资源的属性,Terraform 就能自动识别依赖。例如 VPC 与子网:
resource "aws_vpc" "main" {
cidr_block = "10.20.0.0/16"
tags = { Name = "prod-vpc" }
}
resource "aws_subnet" "app" {
vpc_id = aws_vpc.main.id
cidr_block = "10.20.1.0/24"
tags = { Name = "prod-app-subnet" }
}
这里 aws_subnet.app 通过 aws_vpc.main.id 建立了隐式依赖,Terraform 会先创建 VPC,再创建子网。隐式依赖是首选方式,因为它随代码变化自动更新,不需要人工维护。
显式依赖使用 depends_on,用于表达“没有属性引用、但存在真实先后关系”的场景。典型例子是 IAM 策略与业务资源:策略本身不引用实例,但实例启动前必须已具备权限。
resource "aws_iam_role_policy_attachment" "app" {
role = aws_iam_role.app.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
resource "aws_instance" "app" {
ami = "ami-0example1234567890"
instance_type = "t3.medium"
depends_on = [aws_iam_role_policy_attachment.app]
}
使用 depends_on 的原则是“能隐式就不显式”。显式依赖会强制整条链路串行,降低并行度,也容易掩盖本应通过属性引用表达的真实关系。它更适合处理权限生效、外部系统就绪、跨模块副作用等无法用属性表达的约束。
二、生命周期元参数:改变默认行为
Terraform 为每个资源提供 lifecycle 块,用于覆盖默认的创建、更新、销毁策略。常用参数如下:
create_before_destroy:先创建新资源,再销毁旧资源。适用于负载均衡器、证书、实例等“先有替代品再下线”的场景,可减少服务中断。prevent_destroy:阻止销毁。对生产数据库、核心存储桶等关键资源设置后,误删配置会直接报错,而不是静默删除。ignore_changes:忽略指定属性的外部变更。例如实例标签被运维脚本修改后,不希望 Terraform 每次 plan 都提示回滚。replace_triggered_by:当指定资源或属性变化时,强制替换当前资源。适合“配置变更必须重建实例”的场景。timeouts:自定义创建、更新、删除的超时时间,适配慢速资源。
resource "aws_instance" "app" {
ami = "ami-0example1234567890"
instance_type = "t3.medium"
lifecycle {
create_before_destroy = true
ignore_changes = [tags["LastScanned"]]
prevent_destroy = false
}
}
需要注意:create_before_destroy 与唯一性约束可能冲突。例如安全组名称、固定 IP 等资源若不允许重名,先创建会失败。此时应改用可生成唯一名称的 name_prefix,或调整依赖顺序。
三、创建与销毁顺序的判定
顺序由依赖图决定,而不是由代码书写顺序决定。创建时,Terraform 从无依赖的节点开始,逐层向后推进;销毁时反向执行。若两个资源之间没有依赖,Terraform 会并行处理,因此不能假设“写在后面的先删”。
当出现循环依赖时,terraform plan 会直接报错并指出环路。常见诱因是两个资源互相引用属性,或模块之间形成双向依赖。解决方式通常是引入中间资源、拆分模块,或用 depends_on 替代属性引用,但后者要谨慎,避免把本可并行的链路串行化。
四、资源漂移:识别与处理
资源漂移指真实云上状态与 Terraform state 不一致。常见来源包括:控制台手工修改、其他自动化工具变更、云厂商侧默认值调整、资源被外部删除。漂移不会自动消失,必须通过 plan 暴露出来。
处理漂移的标准流程是:
- 执行
terraform plan,观察哪些资源被标记为 update、replace 或 destroy。 - 判断漂移是否符合预期。若是人为误操作,优先让 Terraform 把资源拉回配置描述的状态。
- 若外部变更才是正确状态,则更新代码,使配置与真实状态一致,再执行 apply。
- 对无法通过配置表达的外部变更,使用
ignore_changes明确声明“不管理该属性”。 - 对已被外部删除的资源,执行
terraform apply重建,或用terraform state rm解除管理后再决定是否重新导入。
terraform plan -detailed-exitcode,退出码为 2 表示存在差异,可把漂移检测纳入日常流水线,而不是等到发布时才发现。terraform refresh 或 apply -refresh-only 盲目覆盖漂移。刷新只更新 state,不改变真实资源;若真实资源已被误删,刷新后 state 会丢失该资源,后续 apply 可能触发重建,需先确认影响范围。五、实践检查清单
| 检查项 | 判断标准 | 处理建议 |
|---|---|---|
| 依赖是否隐式表达 | 参数中是否引用了上游资源属性 | 能引用就不写 depends_on |
| depends_on 是否必要 | 是否存在无属性引用的真实先后约束 | 仅用于权限、外部就绪等场景 |
| 关键资源是否防误删 | 数据库、存储桶是否设置 prevent_destroy | 生产环境建议开启 |
| 替换是否平滑 | 实例、证书是否使用 create_before_destroy | 注意唯一性约束冲突 |
| 漂移是否可控 | plan 是否出现非预期变更 | 先判断再 apply,必要时 ignore_changes |
依赖管理和生命周期控制是 Terraform 从“能跑”走向“可运维”的分水岭。隐式依赖保证图正确,显式依赖补齐语义,生命周期参数控制风险,漂移处理维持配置与现实的同步。把这四件事纳入日常流程,资源生命周期才真正可预期。