TT Lab
开始
学习 学习路径 课程

Terraform/OpenTofu 基础

只需改状态,差点把资源重建一遍

在 TT Lab 中继续学习

目标

用 OpenTofu 逐一确认:刷新专用计划与应用、不读取实物的计划所带来的错觉、保存下来的销毁计划、销毁的逆序、缩小对象范围的销毁所给出的警告,以及全部删除之后状态中还剩下什么。

为什么重要

计划比较两样东西——代码与状态,以及状态与实物。能把这两者分开处理,是刷新类命令的核心。如果只是状态与实物不一致,就可以不动代码,只让状态对齐,这样就不必重新创建资源。反过来,如果不读取实物就生成计划,工具就会把状态中记录的值当作事实。这是用准确度换取大型仓库中速度的选择,用这样生成的计划去获得批准,就会在不一致的情况下被应用。销毁一侧也是顺序决定一切。必须按创建顺序的逆序删除,仍然留着的东西才不会指向已经消失的东西。缩小对象范围来删除,会破坏这一保证,所以工具会附上警告。最后,要知道即使全部删除,状态文件本身也会保留,才不会把“删除状态”和“删除资源”混为一谈。

步骤

  1. 在 /root/tfb-refresh/base/main.tf 中放置向 app.conf 写入一行 mode=managed 的 local_file.conf,以及把该资源的 id 以一行 conf=<id> 写入 audit.txt 的 local_file.audit。执行 init·apply,并确认计划是干净的。
  2. 不经过工具,把 /root/tfb-refresh/base/app.conf 改成一行 HANDEDIT。然后把 tofu plan -refresh-only 的输出保存到 /root/tfb-refresh/refresh-plan.txt。暂时不要应用任何东西。
  3. 在同一目录中,把 tofu plan -refresh=false 的输出保存到 /root/tfb-refresh/norefresh.txt,把普通的 tofu plan 的输出保存到 /root/tfb-refresh/withrefresh.txt。确认这两份输出有什么不同。仍然不要应用。
  4. 运行 tofu apply -refresh-only -auto-approve。然后在 /root/tfb-refresh/refresh-report.txt 中写入四行——serial_before=<새로고침 직전 상태의 serial>、serial_after=<지금 serial>、resources_after=<지금 상태의 리소스 수>、conf_first_line=<지금 디스크의 app.conf 첫 줄>(占位符依次为刷新前状态的 serial、当前的 serial、当前状态中的资源数量、当前磁盘上 app.conf 的第一行内容)。之前的状态保留在备份文件中。
  5. 在 /root/tfb-refresh/chain/main.tf 中把三个 terraform_data 放成一条链——net、引用其 output 的 db、引用后者 output 的 app。三者都带有一个在销毁时把自己的名称追加到 /root/tfb-refresh/chain/order.log 的 provisioner,并放置导出 app.output 的输出 chain。执行 init·apply 之后,用 tofu plan -destroy -out=destroy.tfplan 保存计划,再用 tofu show -json 把待删除对象的地址按字典序逐行写入 /root/tfb-refresh/destroy-targets.txt。
  6. 原样应用保存下来的 destroy.tfplan,把这条链删除。查看 /root/tfb-refresh/chain/order.log 中留下的顺序,并把同样的顺序逐行写入 /root/tfb-refresh/order.txt。
  7. 在 /root/tfb-refresh/tgt/main.tf 中放置一条同样形态的链(net·db·app),不带 provisioner,并执行 init·apply。然后用 tofu destroy -target=terraform_data.app -auto-approve 只删除最末端的一个,把输出保存到 /root/tfb-refresh/target-destroy.txt。把剩余状态的地址按字典序写入 /root/tfb-refresh/target-left.txt。
  8. 把 /root/tfb-refresh/chain 销毁之后的状态与备份文件对照,在 /root/tfb-refresh/leftover.txt 中写入四行——resources=<지금 상태의 리소스 수>、outputs=<지금 상태의 출력 수>、lineage_changed=<yes 또는 no>、serial_up=<yes 또는 no>(占位符依次为当前状态中的资源数量、当前状态中的输出数量、yes 或 no、yes 或 no)。然后再运行一次 tofu plan,把输出保存到 /root/tfb-refresh/after-destroy-plan.txt。

参考

创建基线

在 /root/tfb-refresh/base/main.tf 中放置向 app.conf 写入一行 mode=managed 的 local_file.conf,以及把该资源的 id 以一行 conf=<id> 写入 audit.txt 的 local_file.audit。执行 init·apply,并确认计划是干净的。

local provider 的文件资源把内容的哈希用作 id。所以内容一变,id 就会变,引用该 id 的资源也会随之动摇。

用刷新专用计划查看外部发生的变化

不经过工具,把 /root/tfb-refresh/base/app.conf 改成一行 HANDEDIT。然后把 tofu plan -refresh-only 的输出保存到 /root/tfb-refresh/refresh-plan.txt。暂时不要应用任何东西。

刷新专用计划不是“让代码符合实物”的计划,而是“让状态符合实物”的计划。所以输出中显示的不是 create 或 destroy,而是状态中消失了什么。

不读取实物的计划会说什么事都没有

在同一目录中,把 tofu plan -refresh=false 的输出保存到 /root/tfb-refresh/norefresh.txt,把普通的 tofu plan 的输出保存到 /root/tfb-refresh/withrefresh.txt。确认这两份输出有什么不同。仍然不要应用。

如果不读取实物,工具就会把状态中记录的值当作事实。这是为了在大型仓库中快速生成计划而使用的选项,但如果用这样的计划去获得批准,就会在与实物不一致的情况下被应用。

只修改状态,不触碰实物

运行 tofu apply -refresh-only -auto-approve。然后在 /root/tfb-refresh/refresh-report.txt 中写入四行——serial_before=<새로고침 직전 상태의 serial>、serial_after=<지금 serial>、resources_after=<지금 상태의 리소스 수>、conf_first_line=<지금 디스크의 app.conf 첫 줄>(占位符依次为刷新前状态的 serial、当前的 serial、当前状态中的资源数量、当前磁盘上 app.conf 的第一行内容)。之前的状态保留在备份文件中。

这条命令一点实物也不会改变。改变的只有状态,工具会把之前的状态保存为备份文件。手工修改过的文件必须保持原样。

把销毁计划保存为文件并评审

在 /root/tfb-refresh/chain/main.tf 中把三个 terraform_data 放成一条链——net、引用其 output 的 db、引用后者 output 的 app。三者都带有一个在销毁时把自己的名称追加到 /root/tfb-refresh/chain/order.log 的 provisioner,并放置导出 app.output 的输出 chain。执行 init·apply 之后,用 tofu plan -destroy -out=destroy.tfplan 保存计划,再用 tofu show -json 把待删除对象的地址按字典序逐行写入 /root/tfb-refresh/destroy-targets.txt。

销毁计划也可以像普通计划一样保存为文件,保存下来的文件既可以用供人阅读的格式查看,也可以用机器可读的格式查看。越是像销毁这样无法撤销的操作,越应该保存计划并评审,然后只应用那个文件,这样更安全。

删除的顺序是创建顺序的逆序

原样应用保存下来的 destroy.tfplan,把这条链删除。查看 /root/tfb-refresh/chain/order.log 中留下的顺序,并把同样的顺序逐行写入 /root/tfb-refresh/order.txt。

创建时,被依赖的对象必须先被创建;删除时则必须相反。否则仍然留着的东西就会指向已经消失的东西。不要重新生成计划,而是应用保存下来的文件。

缩小对象范围的销毁会带着警告出现

在 /root/tfb-refresh/tgt/main.tf 中放置一条同样形态的链(net·db·app),不带 provisioner,并执行 init·apply。然后用 tofu destroy -target=terraform_data.app -auto-approve 只删除最末端的一个,把输出保存到 /root/tfb-refresh/target-destroy.txt。把剩余状态的地址按字典序写入 /root/tfb-refresh/target-left.txt。

缩小对象范围的选项,是声明由人来承担工具平时所守护的整张图的一致性。所以输出中会带有警告。只在紧急情况下使用,用过之后,运行一次不缩小范围的计划来确认。

全部删除之后状态中剩下什么

把 /root/tfb-refresh/chain 销毁之后的状态与备份文件对照,在 /root/tfb-refresh/leftover.txt 中写入四行——resources=<지금 상태의 리소스 수>、outputs=<지금 상태의 출력 수>、lineage_changed=<yes 또는 no>、serial_up=<yes 또는 no>(占位符依次为当前状态中的资源数量、当前状态中的输出数量、yes 或 no、yes 或 no)。然后再运行一次 tofu plan,把输出保存到 /root/tfb-refresh/after-destroy-plan.txt。

即使全部删除,状态文件本身也会保留。只有知道什么变空、什么保留下来,才不会把“删除状态”和“删除资源”混为一谈。销毁之前的状态在备份文件中。