← 中文资源

简体中文版本

启用 Terraform State 锁并安全解锁

通过条件写入或 DynamoDB 表实现远程状态加锁,并确认没有 apply 在运行后再执行 force-unlock,避免并发写入损坏 state。

阅读英文原文

概述

Terraform 的执行过程是读取 state、计算差异、调用云 API、写回 state。两个针对同一份 state 的运行可能交错执行,最终写出既不描述旧状态也不描述新状态的中间结果。加锁通过让后端在运行期间记录持有者来串行化这个过程。S3 加 DynamoDB 是长期使用的标准方案,较新的 Terraform 可以用 use_lockfile = true 配合 S3 条件写入,省去额外的表。无论哪种方式,只有所有写入方都遵守锁才有意义,因此流水线和人工操作必须使用同一套后端配置。

步骤

  1. 配置带锁与加密的远程后端:
terraform {
  backend "s3" {
    bucket         = "acme-tfstate"
    key            = "payments/prod.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "acme-tfstate-locks"
    encrypt        = true
  }
}
  1. 同时启动两个 plan,确认锁生效:
terraform plan -lock-timeout=0 & terraform plan -lock-timeout=0; wait
  1. 解锁前先检查锁的持有者:
aws dynamodb get-item --table-name acme-tfstate-locks \
  --key '{"LockID":{"S":"acme-tfstate/payments/prod.tfstate"}}'
  1. 只解锁已确认的具体锁 ID:
terraform force-unlock "$LOCK_ID"

验证

第二个并发 plan 应立即失败,并输出锁 ID 与创建时间,而不是等待超时;检查锁记录后应能看到持有者与时间戳。解锁后新的 plan 应正常获取锁。若怀疑 apply 被中断,解锁后立即执行只读 plan 或 refresh,确认 state 与云端一致,再继续发布。

注意事项

  • 锁只保护 state 写入,不保护云 API,资源命名冲突仍需通过唯一命名解决。
  • force-unlock 会跳过安全检查,滥用可能导致两个写入方同时运行。
  • 取消 CI 任务后应等待进程真正退出再解锁,避免仍在执行的 apply 继续写入。
  • 使用 use_lockfile 需要 Terraform 1.10 及以上,并依赖 S3 条件写入。
  • 在非生产环境演练一次“进程被杀—检查锁—解锁—重新 plan”的流程。