LabHub
学习 学习路径 课程

Terraform 实战

状态手术 — 不碰实物,只修记忆

在 LabHub 中继续学习

一句话总结

state mvstate rm不改变基础设施。**只改变工具的记忆。**如果误解这句话就会出事故,理解的话就会使重构变得安全。

概念图: 只改变工具的记忆。 · 旧名称的资源消失了,新名称的资源出现了 · 移动地址 · 把外面的东西拿过来

为什么需要这个?

基础设施代码必须经历重构。因为不喜欢资源的名字,所以想把几个资源打包成模块,因为状态文件太大,所以想分开。但是,在代码中更改名称的瞬间,工具判断旧名称的资源消失了,新名称的资源出现了。在计划中,破坏和创造并列出现。如果是实际运营DB的话,批准那个计划的瞬间就是结束。

也有相反方向的问题。在应对障碍时,有人在控制台上创建了安全组。虽然实体存在,但代码和状态中没有。下面的apply不知道该资源,所以没有触动它,但增加了一个没有人管理的资源。把这个资源带到代码管理下import全部。

这两种方向——移动地址把外面的东西拿过来——就是状态手术的全部。

怎么行动

状态文件是记录“我制作的资源的地址和最后知道的属性”的账簿。手术工具有四个。

命令 做的事情 对实物的影响
state list 输出地址列表
state show <주소> 那个地址的所有属性输出
state mv A B 将账簿中的A项目改名为B名
state rm A 在账簿中删除A项目 (实物保持原样)
import 将实物登记在账簿上

最常被误解的是state rm是的。这不是删除命令,而是管理放弃宣言。实物保持原样,只忘记工具。所以state rm在后面的代码中,如果不删除该块,下一步计划就会说“没有那个资源,重新创建吧”。在实际的云中,试图再创建名称重叠的资源时会失败,最坏的情况是产生重复资源。如果想删除实物的话destroy应该用。

state mv用代码做像这样的事情moved是区块。差异在记录中。state mv在某人的终端上执行一次后就会消失,moved留在代码中,团队成员plan即使转了10万韩元,也会自动发生同样的移交。所以单独使用的状态下state mv,在许多人使用的代码中moved 是基础。

import也有两种形式。命令行tofu import <주소> <ID>立即执行并改变状态。import {}区块在代码中进行声明,先用计划确认后通过apply反映。后者可以进行评论,并留下履历,所以在协作中区块方式更好。两者都必须**提前创建要带入的位置(资源区块)**这一点是一样的。如果没有空壳,工具可能不知道该把那个ID放在哪里。

在现场相遇的样子

**第一,手术前副本不是谈判对象。**在触摸状态的所有命令之前,请复制文件。如果是远程后端的话state pull接收。虽然很难恢复错误移动的地址,但如果有副本的话,只要恢复就可以了。确认副本是否真实的方法是lineage比较价格——必须是具有相同状态的文件。

**第二,状态损坏通常来自中断的apply。**如果网络中断后apply崩溃,文件就会损坏。通过远程后端的版本管理恢复以前版本apply -refresh-only将实物再次匹配是标准的恢复程序。只有一个本地文件运行的情况是危险的真正原因。

**第三,import后必须阅读第一个计划。**如果带来的资源的实际属性与代码不同,计划会试图消除差异。在将从控制台创建的资源的详细设置写入代码之前,如果apply的话,一进来就丢失了设置。import后prevent_destroy暂时挂起来也是常见的防御策。

**第四,转移状态的工作要和锁定一起考虑。**在多人使用的远程状态下,在手术中如果别人操作apply,就无法预测结果。通知工作时间,如果可能的话,暂时停止管道。

在处理状态之前必须做的

state rmstate mvimport虽然不会触动实际资源,但**Terraform会改变世界。 改变看待的眼光。**如果做错了,活着的资源就会被管理之外,下一个apply就会 删除那个。

**首先接收状态。**即使是远程后端,也会在本地留下副本。

terraform state pull > state.backup.json
terraform state list | tee resources.txt

决定是否有办法回溯,是否有办法依靠。

import只在状态中放入。如果没有代码,下一步计划中会出现“删除”。 所以顺序是先写代码,然后import,确认计划是否有效。 如果计划没有,意味着代码与实际资源不同,所以调整代码。

terraform plan -generate-config-out=generated.tf   # 코드 초안을 만들어 준다
terraform import aws_s3_bucket.logs my-logs-bucket
terraform plan     # 여기서 "No changes" 가 나와야 끝난 것이다

import如果把区块写在代码上的方式,可以在计划中提前看到,更安全。

import {
  to = aws_s3_bucket.logs
  id = "my-logs-bucket"
}

**state rm不是放弃资源,而是放手。**实际资源保持原样 只忘记了南高Terraform。用在移动到其他堆栈时,在移动到要移动的地方之前导入之前 因为会变成没有人管理的状态,所以在这期间没有人apply。

移动模块时,地址会全部变更。 一个资源一个state mv与其这样做 moved使用区块的话,会出现在计划中并接受审查。状态操作的记录是 虽然没有留下,但在代码中写下的移动会在提交中留下。

在操作之前确认是否有锁。 CI 运行期间如果修复状态,两边就会 上传彼此不同的状态。

下次实习要做的事情

首先打印副本,然后查看状态,state mv更改资源名称并确认计划是否被覆盖。用同样的命令将资源移动到模块内,state rm用计划证明不会删除这个实物的事实。然后import {}区块和tofu import命令用两种方法将外部资源纳入状态,最后-detailed-exitcode用代码证明和状态完全一致,用终止代码证明。