CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
State 管理 本地 state、远程 backend、锁。
State 管理
这一课你将能做到
说清楚 state 文件里存了什么、Terraform 为什么离不开它
把本地 state 迁移到 S3 + DynamoDB 远程后端,理解锁的工作方式
用 import、state mv、state rm、state list 处理资源纳入管理、改名和摘除
为什么要学
State 是 Terraform 的命门,也是初学者最容易惹祸的地方:误删 state 文件,Terraform 下次 apply 会把整套资源「再建一遍」;多人共用本地 state,会互相覆盖;有人离职留下一台控制台手建的老机器,需要 import 纳管;重命名资源块不做 state mv,结果是删旧建新。日常运维工作里,和 state 打交道的频率不亚于写资源本身。这一课全是保命操作。
人话:state 像房产登记簿——房子本身在云上架着,但「这套房子归 Terraform 的哪个配置项管」全靠登记簿证明。簿子丢了或写错了,不是房子没了,而是 Terraform「不认识」房子了,后果往往比房子没了更麻烦。
先建立图像
State 的三大职责:
1. 映射:配置地址 (aws_instance.app) ↔ 真实资源 ID (i-0abc123)
2. 缓存:记录云端属性,减少 plan 时的 API 调用
3. 同步:远程后端 + 锁,保证同一时刻只有一人/一个流水线在改
本地后端 vs 远程后端:
维度 本地(默认) S3 远程后端 文件位置 目录下 terraform.tfstate S3 桶中的 key 多人协作 不可行 天然共享 并发锁 无 DynamoDB 表锁 版本历史 无 S3 版本化可回滚 加密 依赖磁盘 SSE 加密 + 桶策略
跟着做
步骤 1:观察本地 state
用上一课的 plan-demo 目录,apply 后执行:
terraform state list
输出当前管理的全部资源地址,如 null_resource.app[0]。查看某个资源的详细状态:
terraform state show null_resource.app[0]
直接看文件:terraform.tfstate 是 JSON,里面能找到资源 ID、属性、依赖关系。注意它默认是明文,包含数据库地址等敏感信息,所以团队场景必须上远程后端。
步骤 2:准备 S3 后端底座
先手动(或用另一个 Terraform 配置)创建:一个开启版本化和加密的 S3 桶、一张 DynamoDB 表(主键名为 LockID,类型 String)。
用 AWS CLI 示例:
aws s3api create-bucket --bucket my-tfstate-12345 --region ap-northeast-1 \
--create-bucket-configuration LocationConstraint=ap-northeast-1
aws s3api put-bucket-versioning --bucket my-tfstate-12345 \
--versioning-configuration Status=Enabled
aws dynamodb create-table --table-name tf-locks \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
桶名必须全局唯一,换成你自己的。
步骤 3:配置远程后端并迁移 terraform {
backend "s3" {
bucket = "my-tfstate-12345"
key = "plan-demo/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}
Terraform 检测到后端从 local 变为 s3,会提示:
Do you want to copy existing state to the new backend?
输入 yes,本地 state 被上传到 S3,之后本地不再保留权威副本。去 S3 控制台能看到该 key,桶版本历史里有第一个版本。
步骤 4:观察锁 保持一个 apply 正在运行时,另开终端再跑 apply,会得到类似:
Error: Error acquiring the state lock
... Lock ID: 一串 UUID
这就是 DynamoDB 锁在防止并发写。操作正常结束后锁自动释放。确认持锁进程已经死掉(比如流水线任务被删除)才能:
terraform force-unlock <锁ID>
别在操作正常运行时强解,否则 state 可能被写坏。
步骤 5:import 纳管已有资源 场景:一台控制台手工创建的 EC2(i-0abcd1234)要纳入 Terraform。
Terraform 1.7 的 import 有两种形式。先看经典形式——先在配置里写一个空壳资源:
resource "aws_instance" "legacy" {}
terraform import aws_instance.legacy i-0abcd1234
成功后 state 中出现该资源,随后 terraform plan 会提示你「配置参数缺失,需要补齐」——按 plan 提示把属性补进资源块,直到 plan 无差异为止。
Terraform 1.7 还支持声明式 import 块(推荐,可进 CI):
import {
to = aws_instance.legacy
id = "i-0abcd1234"
}
plan 阶段即可预览导入结果,apply 时完成导入,之后删掉 import 块。
步骤 6:state mv 重命名 resource "aws_instance" "app" { ... }
terraform state mv aws_instance.legacy aws_instance.app
这样 plan 不会显示「删 legacy、建 app」,资源原地保留。跨模块迁移同样用 mv,写法为 module.old.aws_instance.x → module.new.aws_instance.x。
步骤 7:state rm 摘除管理 只想让 Terraform「别再管这个资源」,但保留云端对象:
terraform state rm aws_s3_bucket.temp
资源从登记簿消失,云端对象不受影响;之后可手工删除或交给别人。rm 不删资源,destroy 才删资源——两者绝不能混。
讲清楚要点
备份 state 再动手 :操作 state 前先 terraform state pull > backup.tfstate 存一份,出问题能回推。
S3 后端支持多环境分 key :如 prod/terraform.tfstate、staging/terraform.tfstate,或干脆每个环境一个独立配置目录/桶前缀。
敏感数据会进 state :数据库密码、用户数据都可能明文存在 state 中,桶策略要收紧、日志里别贴 state 全文。
state 操作只改登记簿 :mv/rm 都不碰真实资源;它们解决「配置地址」和「资源 ID」的对应问题。
workspace 不是多环境银弹 :workspace 能在同一后端隔离 state(state 路径带 env 前缀),适合临时/小差异环境;强隔离的生产环境更推荐独立目录或独立后端,第 10 课再细讲。
你可能会懵的地方
state 文件丢了怎么办?
远程后端靠 S3 版本化恢复;本地丢失只能靠资源 ID 逐个 import 重建映射。预防比补救便宜,这也是必须上远程后端的原因。
为什么 plan 说资源不存在但我在控制台看得到?
那是没被 state 登记的资源,Terraform 不认识它。需要 import,或者它本来就该由别的系统管理。
import 之后 plan 为什么还有一堆要改?
import 只搬「身份映射」,你配置里的参数和云端实际属性还没对齐。按 plan 逐项补齐配置是 import 的必要后半程。
能让 state 里的密码不明文吗?
没有可靠的字段级加密方案。正确做法是限制谁能读 state 桶,并尽量把密钥放到 Secrets Manager,在资源里引用而非写入。
terraform state pull 有什么用?
手工查看远程 state、做备份、或排查流水线问题。pull 是只读获取,想推回要用 push(极少需要,风险高)。
错法对照 错法 问题 正解 直接删 state 文件「重来」 apply 时重复创建全套资源 state rm 精确摘除,或先备份 改本地名不做 state mv 资源被删旧建新 改名 + terraform state mv 控制台手建资源不 import Terraform 视野外的野资源 import 纳管并补齐配置 S3 桶不开版本化 state 写坏无法回滚 创建桶时开启 versioning + 加密 不确认就 force-unlock 并发写坏 state 确认持锁进程已终止再解
卡点急救
state lock 一直不释放 :先查 DynamoDB 表里的锁记录和持锁人信息,确认对应流水线/进程已结束,再 force-unlock。
init 迁移后端失败中断 :修复后端参数(桶名、权限)后重跑 init,它会再次询问迁移;必要时用 -reconfigure 或 -migrate-state。
state 疑似损坏 :用 terraform state pull 导出,对比备份;无法修复时从最近的 S3 版本恢复,再 plan 验证。
面试常问
Terraform state 的作用?为什么推荐远程 state?
state 维护配置地址与真实资源 ID 的映射、缓存属性、支撑协作同步。远程后端提供共享存储、加密、版本历史和并发锁,解决本地 state 无法协作、易丢失、易泄露的问题。
如何把一台手工创建的机器纳入 Terraform 管理?
写资源块,用 terraform import(或 import 块)把云资源 ID 关联到配置地址,然后按 plan 输出补齐参数直到无差异,此后变更全部走代码。
state mv 和 state rm 的区别?分别在什么场景用?
mv 改变资源在登记簿中的地址(重命名/跨模块),真实资源不动;rm 把资源从登记簿摘除(不再管理),云端对象保留。两者都不会删除真实资源。
自测三问
为什么误删 state 不等于资源被销毁?它会造成什么实际后果?
S3 后端中 DynamoDB 表扮演什么角色?不开它会怎样?
import 一台 EC2 后,还差哪一步才算「真正纳管」?
小结一句话 state 是配置与现实之间的登记簿:上 S3+DynamoDB 远程后端解决共享与锁,import 纳管存量、mv 改名、rm 摘管,动手前先 pull 备份。
延伸