变更流程
本章目标:建立一套「可预览、可评审、可回滚」的 Terraform 变更流程——从本地 plan / apply,到把 plan 接进 CI 做门禁。这是把「玩具脚本」变成「生产工程」的分水岭。
完成后你应能在 PR 里评审 Terraform 变更,并理解 CI 中跑 plan 的标准姿势。
1. 标准本地流程
terraform fmt -recursive # 1. 格式化
terraform validate # 2. 静态校验
terraform plan -input=false -out=tfplan # 3. 生成计划文件
terraform show -no-color tfplan # 4. 人工审阅计划
terraform apply tfplan # 5. 按审阅过的计划执行
要点:
plan -out=tfplan再apply tfplan:确保你审阅的和执行的是同一份计划,避免审阅后、执行前代码又被改。tfplan含敏感信息概览,别提交进 Git;用.gitignore忽略*.tfplan。- 生产环境不要直接
terraform apply(无计划文件),那等于盲操作。
2. 怎么读 plan
plan 输出每个资源一行动作标记:
| 标记 | 含义 |
|---|---|
+ | 新建(create) |
- | 销毁(destroy) |
~ | 原地更新(in-place update) |
-/+ | 销毁后重建(replace) |
<= / => | 数据源刷新 |
replace(-/+)尤其要警惕,它意味着** downtime**:比如改了 aws_instance 的 ami,Terraform 会先删旧的再建新的(除非配了 create_before_destroy)。
# aws_instance.web will be created
+ resource "aws_instance" "web" {
+ ami = "ami-0abcd1234"
+ instance_type = "t3.small"
}
# aws_db_instance.main must be replaced
-/+ resource "aws_db_instance" "main" {
~ allocated_storage = 20 -> 100 # 这一改触发重建
}
任何 -/+ 都要追因:是改了不可变字段(如资源 ID、AZ)吗?能否避免?对数据库、有状态服务,重建 = 丢数据/断服务,必须走评审 + 备份。
3. 缩小变更范围与精准定位
-
-target:只针对某资源跑计划(排障、紧急修一个资源时用)。terraform apply -target=aws_security_group.web-target是逃生舱,不是日常它只算显式目标,可能留下不一致(依赖它的资源没同步)。仅限排障/紧急,正常流程始终跑全量
plan。 -
terraform graph/terraform plan -out配合terraform show -json:把计划转 JSON 供工具分析(CI、策略校验用)。
4. 把 plan 接进 CI(门禁)
目标:每次 PR 只预览、不执行;apply 只在对评审过的计划触发,且通常由流水线完成。
# 伪代码:CI 的两个阶段
plan:
steps:
- run: terraform fmt -check -recursive
- run: terraform init -input=false
- run: terraform validate
- run: terraform plan -input=false -out=planfile
- run: comment_plan_on_pr(planfile) # 把 plan 贴到 PR 评论
- run: upload_artifact(planfile) # 仅供同一流水线的 apply 使用
apply: # 仅在同一提交的 plan 通过审批后
needs: plan
steps:
- run: download_artifact(planfile)
- run: terraform init -input=false
- run: terraform apply -input=false planfile
关键环境变量与参数:
| 变量 / 参数 | 作用 |
|---|---|
TF_IN_AUTOMATION=1 | 关闭交互提示、弱化非必要输出 |
-input=false | 禁止交互式询问(CI 里必须) |
terraform plan -detailed-exitcode | 0=无变更、2=有变更、1=执行错误,便于 CI 判定 |
terraform show -json planfile | 输出 JSON,供策略工具/评论渲染 |
plan 阶段生成的 planfile 应作为构建产物传给同一提交、同一流水线的 apply 阶段,保证「评审的就是执行的」。若 PR 合并后会重新触发流水线,则必须重新生成并评审该 merge commit 的 plan,不能拿旧提交的产物直接 apply。用临时存储/OIDC 短期凭据,别把长期 AK 放 CI 变量里(见第 9 章)。
常见工具链:Atlantis(PR 评论里跑 plan/apply)、Terraform Cloud(原生 run 流程)、或自研 GitHub Actions + terraform-plan 评论机器人。
5. 漂移检测(drift detection)
Terraform 的 plan 本质是「代码 vs state vs 真实」的三方 diff。若有人手动改了云上资源,state 就和实际不符——这种「漂移」要定期发现:
# 定时任务(如每日)只刷新 state;退出码 2 表示检测到漂移
terraform plan -refresh-only -detailed-exitcode
# 0 = 无漂移,2 = 有漂移,1 = 执行错误
普通 plan 会同时包含代码改动和漂移,不能把「有变更」直接等同于漂移;定时巡检应使用上面的 -refresh-only。两种 plan 都不会改云资源,只有 apply 才会写入 state 或改变云资源。
6. PR 评审清单
审 Terraform 变更时重点看:
- 范围:
+ / - / ~ / -/+数量是否符合预期?有没有「顺手多改了不相干的资源」? - replace 原因:每个
-/+是否必要?有状态服务重建有没有备份/停机预案? - IAM / 安全:新资源是否暴露公网?安全组是否开了
0.0.0.0/0?加密开了吗? - 成本:加了什么规格的实例/RDS?会不会意外升配?
- 敏感信息:有没有把密码/密钥写死在代码或计划里?
- state 影响:动了 backend / 改名资源?是否配套
state mv?
7. 练习与验收
练习 A
- 对本地的
envs/staging做一次plan -out=tfplan并人工审阅 - 故意改一个会触发
replace的字段,观察 plan 里-/+的出现与原因
练习 B
- 写一段最小 CI 配置:PR 时
init -input=false+validate+plan -detailed-exitcode - 把
plan输出贴到 PR 评论(可手动模拟terraform show -no-color tfplan的内容)
验收清单
- 能用
plan -out+apply <file>保证「审执行一致」 - 能看懂
+ / - / ~ / -/+并能解释 replace 风险 - 懂得
-target的局限,仅作排障用 - 能把
plan接进 CI 做门禁,并理解TF_IN_AUTOMATION/-input=false - 会用
plan -detailed-exitcode做漂移/变更检测
下一章:导入与漂移 —— 把存量资源 import 进 Terraform,并优雅地处理手工改动造成的漂移。