i007.cc

i007.cc

优先队列-降维打击

05.价值资料

terraform的state

Terraform 的 state(状态)是它最核心也最容易踩坑的机制之一。简单说,Terraform 需要知道”现实世界里资源长什么样”才能算出该做什么改动,而 state 就是它用来记录这份现实快照的地方。

为什么需要 state

Terraform 的配置文件描述的是”期望状态”(desired state),但云厂商的 API 本身并不会告诉 Terraform”这个资源是不是我之前创建的””它现在的属性是什么”。所以 Terraform 会在本地(默认)维护一个 terraform.tfstate 文件,里面用 JSON 记录了每个资源的 ID、属性、依赖关系等元数据。每次执行 terraform plan 或 apply 时,它会拿配置文件、state 文件、以及(必要时)实际查询到的资源现状三者做对比,算出一个执行计划。

state 文件里有什么

主要是资源的实际属性值(包括一些你在 HCL 里没写但云端自动生成的字段,比如 ARN、创建时间)、资源之间的依赖图,以及 provider 的元信息。需要注意的是,state 里经常会包含敏感信息(比如数据库密码、私钥),因为这些值即便你标记了 sensitive = true,也依然会明文存在 state 文件里——所以 state 文件本身要当作敏感数据对待,绝对不能提交到 Git 仓库。

本地 state 的问题

默认情况下 state 存在本地磁盘上,这在团队协作时会有几个大问题:一是多人同时 apply 会互相覆盖甚至损坏 state;二是 state 丢了基本等于 Terraform 对这些资源”失忆”,虽然资源还在,但 Terraform 不再知道它们的存在;三是敏感信息只在你本机,不利于团队共享和审计。

远程 state(remote backend)

生产环境几乎都会用远程 backend,比如 AWS S3 + DynamoDB(用于加锁)、Terraform Cloud、Azure Storage、GCS 等。远程 backend 解决了两个关键问题:

一是集中存储,团队所有人和 CI/CD 都读写同一份 state,不会出现”我本地的 state 是旧的”这种情况。二是状态锁(state locking),apply 期间会给 state 加锁,防止两个人同时跑 apply 导致 state 损坏或产生竞态更新。S3 backend 通常搭配 DynamoDB 表做锁,Terraform Cloud/Enterprise 则是内置锁机制。

常见的 state 操作命令

  • terraform state list:列出 state 里管理的所有资源
  • terraform state show <resource>:查看某个资源在 state 中的详细属性
  • terraform state mv:重命名资源或把资源移动到另一个 module,而不触发销毁重建
  • terraform state rm:把资源从 state 中移除(但不删除真实资源),常用于”不想再让 Terraform 管这个资源了”
  • terraform import:把已经存在、但不是 Terraform 创建的资源”认领”进 state
  • terraform refresh(现在通常通过 plan -refresh-only):用真实基础设施的最新状态更新 state,处理”漂移”(drift,即实际资源被人手动改过,和 state 不一致的情况)

state 与 workspace

Terraform 的 workspace 功能允许同一份配置对应多份独立的 state(比如 dev/staging/prod),但这只是轻量级隔离,很多团队更倾向于用不同的目录 + 不同的 backend key 来彻底隔离环境,避免”一不小心在 prod workspace 里跑了 dev 的变更”这种事故。

几个实践建议

千万不要手工编辑 state 文件,容易搞出格式错误或和真实资源脱节;涉及重构资源地址(比如改 module 名字)时用 terraform state mv 而不是删了重建;state 文件(以及它的备份 .tfstate.backup)要加进 .gitignore;团队协作一定上远程 backend + 锁机制;定期跑 plan 检查有没有 drift,防止人工在控制台改动导致配置和现实脱节。

如果你是在处理具体场景(比如 state 冲突、迁移 backend、丢失 state 怎么恢复),可以告诉我具体情况,我可以给更针对性的建议。

发表回复