4. 远程State与后端治理

本地 terraform.tfstate 只适合单人验证。一旦进入团队协作,State 就必须被当作“生产数据库”来治理:它记录资源与真实基础设施的映射关系,任何并发写入、误删或版本回退都可能让 Terraform 认为资源不存在,从而触发重复创建或错误销毁。本节围绕后端选型、锁机制、版本控制、共享隔离和损坏恢复五个方面展开。

一、State 存储选型:先看约束,再看产品

选型的核心不是“哪个后端最流行”,而是四个约束:是否支持原生锁、是否支持版本化、是否支持加密与访问审计、是否与现有身份体系集成。常见后端对比如下。

后端锁机制版本控制适用场景
local无无单人实验、临时验证
S3 + DynamoDBDynamoDB 条件写入S3 版本控制 + 对象锁AWS 为主、跨团队共享
Azure BlobBlob LeaseBlob 版本 + 软删除Azure 生态
GCS对象 generation 前置条件Object VersioningGCP 生态
Terraform Cloud/Enterprise平台内置平台内置历史需要审批、策略、Run 编排
PostgreSQL行级锁需自行实现已有数据库运维能力

以 S3 为例,后端配置通常写成:

terraform {
  backend "s3" {
    bucket         = "acme-tfstate-prod"
    key            = "network/vpc/terraform.tfstate"
    region         = "ap-southeast-1"
    dynamodb_table = "acme-tfstate-lock"
    encrypt        = true
    kms_key_id     = "arn:aws:kms:ap-southeast-1:123456789012:key/abcd-..."
  }
}

其中 key 是隔离边界的关键:不同环境、不同团队、不同资源域应使用不同前缀,而不是共用一个 terraform.tfstate。DynamoDB 表只需一个字符串主键 LockID,Terraform 会在 plan 和 apply 期间写入锁记录,完成后删除。

二、锁机制:谁在写、写多久、卡住怎么办

锁的本质是“同一 State 同一时刻只允许一个写操作”。执行 terraform apply 时,Terraform 先获取锁,再刷新、计划、执行、写回 State,最后释放锁。若锁已被占用,会看到类似提示:

Error: Error acquiring the state lock
Lock Info:
  ID:        8f3c1e2a-...
  Path:      acme-tfstate-prod/network/vpc/terraform.tfstate
  Operation: OperationTypeApply
  Who:       ci-runner@build-07
  Created:   2025-01-12 08:31:44.120 +0000 UTC

处理原则是:先确认持有者是否仍在运行。若 CI 任务已崩溃且锁未释放,可使用 terraform force-unlock <LOCK_ID>,但必须确保没有其他进程正在写同一 State。强制解锁是“最后手段”,不是常规操作。为避免长时间持锁,应把 apply 拆小、避免在 apply 期间做人工审批,并给 CI 设置超时。

三、版本控制与跨团队共享隔离

State 文件本身不应提交到 Git,但 State 的“版本历史”必须保留。S3 开启版本控制后,每次写回都会生成新版本,配合生命周期规则可保留 90 天。恢复时先 aws s3api list-object-versions 找到目标 VersionId,再下载比对,确认无误后回传。

跨团队共享的推荐做法是“按边界拆分 State,用 terraform_remote_state 或数据源只读引用”。例如网络团队维护 VPC State,应用团队通过 data source 读取子网 ID,而不是把 VPC 和应用资源塞进同一个 State。这样锁竞争小、爆炸半径小、权限也能按前缀划分。

远程 State 后端治理:锁、版本、隔离与恢复 网络团队 network/vpc 应用团队 app/order-service 数据团队 data/warehouse DynamoDB 锁表 LockID(主键) 获取 → 刷新 → 计划 执行 → 写回 → 释放 冲突时:force-unlock 需谨慎 S3 远程 State 桶 acme-tfstate-prod network/vpc/terraform.tfstate app/order-service/terraform.tfstate data/warehouse/terraform.tfstate 版本控制:保留 90 天 加密:KMS + 服务端加密 访问:IAM 按前缀授权 持锁写入 State 损坏恢复演练路径 1. 停止所有 apply 确认无持锁进程 2. 列出历史版本 list-object-versions 3. 下载并比对 serial / lineage 4. 回传目标版本 copy-object 5. plan 验证 无意外变更

四、State 损坏的典型表现与恢复演练

State 损坏常见于三种情况:并发 apply 导致后写覆盖前写、误删对象、手工编辑 JSON 破坏结构。表现包括 terraform plan 报 Error: Failed to load state、资源被计划重建、serial 回退导致 Terraform 拒绝写入。恢复前必须先停止所有可能写该 State 的流水线,并确认锁已释放。

恢复演练可按以下步骤执行(示例命令以 S3 为例):

  1. 列出历史版本:aws s3api list-object-versions --bucket acme-tfstate-prod --prefix network/vpc/terraform.tfstate,记录目标 VersionId。
  2. 下载候选版本:aws s3api get-object --bucket acme-tfstate-prod --key network/vpc/terraform.tfstate --version-id <VID> /tmp/state-candidate.json。
  3. 比对关键字段:serial 应大于当前损坏版本,lineage 必须与当前一致,否则说明来自不同 State 谱系,不能直接回传。
  4. 回传:aws s3api copy-object --bucket acme-tfstate-prod --key network/vpc/terraform.tfstate --copy-source acme-tfstate-prod/network/vpc/terraform.tfstate?versionId=<VID>。
  5. 验证:执行 terraform plan,预期输出 No changes 或仅显示已知漂移;若出现大量资源重建,说明回传版本不正确,应重新选择版本。
不要用 terraform state push 覆盖一个 serial 更小的 State,除非明确知道自己在做什么。Terraform 会拒绝 serial 回退,这是保护机制,不是故障。

五、治理清单与常见误区

  • 每个 State 必须有唯一 key 前缀,禁止多团队共用一个 State。
  • 锁表与 State 桶同区域部署,减少跨区延迟与权限复杂度。
  • 开启版本控制、服务端加密、访问日志,并设置保留策略。
  • CI 中禁止 force-unlock 自动执行,必须人工确认。
  • 定期做恢复演练:至少每季度从历史版本恢复一次到隔离环境并跑 plan。
判断 State 是否健康的三个快速信号:terraform plan 无意外变更、serial 单调递增、锁表无残留记录。三者同时满足,才说明后端治理处于可控状态。