TT Lab
はじめる
学ぶ 学習パス コース

Terraform/OpenTofu基礎

状態だけ直せばよいのに資源を作り直しかけた

TT Labで続きを見る

目標

リフレッシュ専用のプランと適用、実物を読まないプランの錯覚、保存した破棄のプラン、破棄の逆順、対象を絞った破棄の警告、そしてすべて削除したあとに状態に残るものまでを、OpenTofuで1つずつ確認します。

なぜ重要なのか

プランは、2つのものを比べます。コードと状態、そして状態と実物です。この2つを別々に扱えるということが、リフレッシュ系のコマンドの核心です。状態が実物と食い違っているだけなら、コードには触れず、状態だけを合わせることができ、そうすればリソースを作り直さなくて済みます。逆に、実物を読まずにプランを出すと、ツールは、状態に書かれた値を事実として信じます。大きなリポジトリで速度を得る代わりに、正確さを手放す選択で、そのようにして出したプランで承認を得ると、食い違ったまま適用が入ります。破棄のほうも、順序がすべてです。作る順序の逆順で削除してはじめて、まだ残っているものが、すでに消えたものを指さずに済みます。対象を絞って削除すると、その保証が崩れるので、ツールが警告を付けます。最後に、すべて削除したあとも、状態ファイル自体は残ることを知っておけば、「状態を削除すること」と「リソースを削除すること」を混同しません。

ステップ

  1. /root/tfb-refresh/base/main.tfに、app.confにmode=managedを1行書くlocal_file.confと、そのリソースのidをconf=<id>の1行でaudit.txtに書くlocal_file.auditを置いてください。init・applyして、プランがきれいかを確認してください。
  2. ツールを経由せずに、/root/tfb-refresh/base/app.confをHANDEDITの1行に変更してください。そのあと、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に保存してください。2つの出力がどう違うかを確認してください。まだ適用しません。
  4. tofu apply -refresh-only -auto-approveを実行してください。そのあと、/root/tfb-refresh/refresh-report.txtに4行を書いてください。serial_before=<새로고침 직전 상태의 serial>、serial_after=<지금 serial>、resources_after=<지금 상태의 리소스 수>、conf_first_line=<지금 디스크의 app.conf 첫 줄>です(プレースホルダーは、順にリフレッシュ直前の状態のserial、現在のserial、現在の状態のリソース数、現在のディスク上のapp.confの1行目です)。直前の状態は、バックアップファイルに残っています。
  5. /root/tfb-refresh/chain/main.tfに、terraform_dataを3つ、連鎖として置いてください。net、そのoutputを参照するdb、そのoutputを参照するappです。3つとも、破棄の時点で、自分の名前を/root/tfb-refresh/chain/order.logに追記するプロビジョナーを持ち、app.outputを出力する出力chainも置いてください。init・applyしたあと、tofu plan -destroy -out=destroy.tfplanでプランを保存し、tofu show -jsonで、削除対象のアドレスを辞書順に、/root/tfb-refresh/destroy-targets.txtに1行ずつ書いてください。
  6. 保存したdestroy.tfplanをそのまま適用して、連鎖を削除してください。/root/tfb-refresh/chain/order.logに残った順序を確認し、同じ順序を/root/tfb-refresh/order.txtに1行ずつ書いてください。
  7. /root/tfb-refresh/tgt/main.tfに、同じ形の連鎖(net・db・app)を、プロビジョナーなしで置いて、init・applyしてください。そのあと、tofu destroy -target=terraform_data.app -auto-approveで、一番端の1つだけを削除して、出力を/root/tfb-refresh/target-destroy.txtに保存してください。残った状態のアドレスを、辞書順に/root/tfb-refresh/target-left.txtに書いてください。
  8. /root/tfb-refresh/chainの破棄後の状態を、バックアップファイルと比べて、/root/tfb-refresh/leftover.txtに4行を書いてください。resources=<지금 상태의 리소스 수>、outputs=<지금 상태의 출력 수>、lineage_changed=<yes 또는 no>、serial_up=<yes 또는 no>です(プレースホルダーは、順に現在の状態のリソース数、現在の状態の出力数、yesまたはnoです)。そして、tofu planをもう一度実行して、出力を/root/tfb-refresh/after-destroy-plan.txtに保存してください。

参考

ベースラインを作る

/root/tfb-refresh/base/main.tfに、app.confにmode=managedを1行書くlocal_file.confと、そのリソースのidをconf=<id>の1行でaudit.txtに書くlocal_file.auditを置いてください。init・applyして、プランがきれいかを確認してください。

localプロバイダーのファイルリソースは、内容のハッシュをidとして使います。そのため、内容が変われば、idが変わり、そのidを参照するリソースも一緒に揺れます。

外で変わったものを、リフレッシュ専用のプランで見る

ツールを経由せずに、/root/tfb-refresh/base/app.confをHANDEDITの1行に変更してください。そのあと、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に保存してください。2つの出力がどう違うかを確認してください。まだ適用しません。

実物を読まないと、ツールは、状態に書かれた値を事実として信じます。大きなリポジトリでプランを速く出すために使うオプションですが、そのプランで承認を得ると、実物と食い違ったまま適用が入ります。

状態だけを直して、実物には触れない

tofu apply -refresh-only -auto-approveを実行してください。そのあと、/root/tfb-refresh/refresh-report.txtに4行を書いてください。serial_before=<새로고침 직전 상태의 serial>、serial_after=<지금 serial>、resources_after=<지금 상태의 리소스 수>、conf_first_line=<지금 디스크의 app.conf 첫 줄>です(プレースホルダーは、順にリフレッシュ直前の状態のserial、現在のserial、現在の状態のリソース数、現在のディスク上のapp.confの1行目です)。直前の状態は、バックアップファイルに残っています。

このコマンドは、実物を1つも変えません。変わるのは状態だけで、ツールは、その直前の状態を、バックアップファイルとして残します。手で直したファイルは、そのままである必要があります。

破棄のプランをファイルに保存して、レビューする

/root/tfb-refresh/chain/main.tfに、terraform_dataを3つ、連鎖として置いてください。net、そのoutputを参照するdb、そのoutputを参照するappです。3つとも、破棄の時点で、自分の名前を/root/tfb-refresh/chain/order.logに追記するプロビジョナーを持ち、app.outputを出力する出力chainも置いてください。init・applyしたあと、tofu plan -destroy -out=destroy.tfplanでプランを保存し、tofu show -jsonで、削除対象のアドレスを辞書順に、/root/tfb-refresh/destroy-targets.txtに1行ずつ書いてください。

破棄のプランも、通常のプランと同じようにファイルに保存でき、保存したファイルは、人が読む形式と、機械が読む形式の両方で見られます。破棄のように元に戻せない作業ほど、プランを保存してレビューしたあと、そのファイルだけを適用するほうが安全です。

削除する順序は、作る順序の逆順である

保存したdestroy.tfplanをそのまま適用して、連鎖を削除してください。/root/tfb-refresh/chain/order.logに残った順序を確認し、同じ順序を/root/tfb-refresh/order.txtに1行ずつ書いてください。

作るときは、依存先が先に作られる必要があり、削除するときは、その反対でなければなりません。そうしないと、まだ残っているものが、すでに消えたものを指すことになります。新しくプランを立てず、保存したファイルを適用してください。

対象を絞った破棄は、警告が付いて出る

/root/tfb-refresh/tgt/main.tfに、同じ形の連鎖(net・db・app)を、プロビジョナーなしで置いて、init・applyしてください。そのあと、tofu destroy -target=terraform_data.app -auto-approveで、一番端の1つだけを削除して、出力を/root/tfb-refresh/target-destroy.txtに保存してください。残った状態のアドレスを、辞書順に/root/tfb-refresh/target-left.txtに書いてください。

対象を絞るオプションは、ツールが普段守ってくれているグラフ全体の一貫性を、人が責任を持つという宣言です。そのため、出力に警告が付きます。緊急時にだけ使い、使ったあとは、対象を絞っていないプランを一度回して確認します。

すべて削除したあとに状態に残るもの

/root/tfb-refresh/chainの破棄後の状態を、バックアップファイルと比べて、/root/tfb-refresh/leftover.txtに4行を書いてください。resources=<지금 상태의 리소스 수>、outputs=<지금 상태의 출력 수>、lineage_changed=<yes 또는 no>、serial_up=<yes 또는 no>です(プレースホルダーは、順に現在の状態のリソース数、現在の状態の出力数、yesまたはnoです)。そして、tofu planをもう一度実行して、出力を/root/tfb-refresh/after-destroy-plan.txtに保存してください。

すべて削除しても、状態ファイル自体は残ります。何が空になり、何が残るかを知っておけば、「状態を削除すること」と「リソースを削除すること」を混同しません。破棄の直前の状態は、バックアップファイルにあります。