只需改状态,差点把资源重建一遍
目标
用 OpenTofu 逐一确认:刷新专用计划与应用、不读取实物的计划所带来的错觉、保存下来的销毁计划、销毁的逆序、缩小对象范围的销毁所给出的警告,以及全部删除之后状态中还剩下什么。
为什么重要
计划比较两样东西——代码与状态,以及状态与实物。能把这两者分开处理,是刷新类命令的核心。如果只是状态与实物不一致,就可以不动代码,只让状态对齐,这样就不必重新创建资源。反过来,如果不读取实物就生成计划,工具就会把状态中记录的值当作事实。这是用准确度换取大型仓库中速度的选择,用这样生成的计划去获得批准,就会在不一致的情况下被应用。销毁一侧也是顺序决定一切。必须按创建顺序的逆序删除,仍然留着的东西才不会指向已经消失的东西。缩小对象范围来删除,会破坏这一保证,所以工具会附上警告。最后,要知道即使全部删除,状态文件本身也会保留,才不会把“删除状态”和“删除资源”混为一谈。
步骤
- 在
/root/tfb-refresh/base/main.tf中放置向app.conf写入一行mode=managed的local_file.conf,以及把该资源的 id 以一行conf=<id>写入audit.txt的local_file.audit。执行 init·apply,并确认计划是干净的。 - 不经过工具,把
/root/tfb-refresh/base/app.conf改成一行HANDEDIT。然后把tofu plan -refresh-only的输出保存到/root/tfb-refresh/refresh-plan.txt。暂时不要应用任何东西。 - 在同一目录中,把
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。
参考
- 销毁的顺序,通过 terraform_data 的销毁时 provisioner 把名称追加到日志文件中,用眼睛来确认。
- 保存下来的计划文件,在应用之后仍然可以读取。像销毁这样无法撤销的操作,应保存计划并评审,然后只应用那个文件。
- 常见错误:第 2·3 步只要求确认,却直接应用了。那样第 4 步要对比的之前的状态就消失了。
- 常见错误:在第 6 步不用保存的计划,而重新运行 destroy 命令。任务是应用保存下来的计划。
- tofu refresh · tofu plan · tofu destroy · terraform_data · State
创建基线
在 /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。
即使全部删除,状态文件本身也会保留。只有知道什么变空、什么保留下来,才不会把“删除状态”和“删除资源”混为一谈。销毁之前的状态在备份文件中。