跳到主要内容

变更流程

本章目标:建立一套「可预览、可评审、可回滚」的 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 # 这一改触发重建
}
看到 replace 先问一句「为什么」

任何 -/+ 都要追因:是改了不可变字段(如资源 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-exitcode0=无变更、2=有变更、1=执行错误,便于 CI 判定
terraform show -json planfile输出 JSON,供策略工具/评论渲染
plan 产物要在 CI 里传递

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

  1. 对本地的 envs/staging 做一次 plan -out=tfplan 并人工审阅
  2. 故意改一个会触发 replace 的字段,观察 plan 里 -/+ 的出现与原因

练习 B

  1. 写一段最小 CI 配置:PR 时 init -input=false + validate + plan -detailed-exitcode
  2. 把 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,并优雅地处理手工改动造成的漂移。