壊すことと手放すことは別の仕事だ
一言でいうと
設定からリソースブロックを削除することは、「壊せ」という意味です。「もう私たちは管理しない」という意味は、removedブロックで別に伝える必要があります。
なぜ必要なのか: 削除と手放しが、同じ文だった
あるチームがデータベースを3台管理していて、そのうち1台を別のチームに引き渡すとします。コードからそのブロックを削除するのが自然に見えます。そして、planを回すと、destroy 1と表示されます。本番稼働中のデータベースです。
以前は、この状況をコマンドで解決していました。状態からそのアドレスを外すコマンドを手で1回打ち、そのあとにコードを削除します。動作はしますが、悪い点が2つあります。1つ目は、記録がないことです。誰がいつ何を状態から外したのかが、コミットに残りません。2つ目は、順序を間違えると終わりであることです。コードを先に削除してapplyを打てば、それで事態は終了です。
removedブロックは、この作業を宣言に移したものです。コードに書かれるので、レビューを受け、コミットに残り、順序が逆になる余地がありません。
どう動くのか
# 1) 리소스 블록을 지운다
# 2) 그 자리에 removed 블록을 둔다
removed {
from = local_file.legacy
}
プランを回すと、次のように出ます。
# local_file.legacy will be removed from the OpenTofu state
# but will not be destroyed
Plan: 0 to add, 0 to change, 0 to destroy.
読み取るべき場所が2か所あります。1つ目は、動作を指す語がdestroyではないことです。2つ目は、そのため、Plan:の行の3つの数字がすべて0であることです。実体には何もしないという意味です。
バージョンによって、受け取る引数が違います。これがこのモジュールで、ぜひ持ち帰ってほしい習慣ですが、removedブロックがlifecycleのような下位ブロックを受け取るかは、使っているバージョンによります。ドキュメントサイトは、デフォルトで最新バージョンを表示するため、ドキュメントにあるからといって、自分のツールが受け取るという保証はありません。確認する方法は簡単です。入れてみてplanを回せば、ツールが直接答えます。ラボのステップ3で、このPodのバージョンが何を受け取り、何を受け取らないかを、直接尋ねて表に書きます。
名前だけを変える作業は、movedです。removedと混同しやすいですが、目的が反対です。movedは、「同じオブジェクトなのにアドレスが変わった」と伝えて、状態の項目を新しいアドレスに移します。これがないと、ツールは、古い名前が消えて新しい名前ができたと解釈して、壊して作り直します。移したのか作り直したのかは、識別子を比べればすぐにわかります。
1つだけ作り直したいときは、-replaceです。設定はそのままにして、「このアドレスだけを壊して作り直せ」をプランに入れます。以前は、同じことをtaintで行っていましたが、違いが重要です。taintは、状態ファイルを先に書き換えておき、次のプランがそれを読むようにします。印を付けたまま忘れると、見当違いの人が、見当違いのタイミングで、その置き換えを適用してしまいます。-replaceは、その実行にだけ適用されるので、痕跡が残りません。それでも、taint・untaintを知っておく必要がある理由は、他人が印を付けておいた状態に出会ったときに、慌てないためです。
現場での姿
最もよくある事故は、removedブロックを片付けずに残しておくことです。作業が終われば、そのブロックは死んだコードですが、死んだまま残っていて、いつかそのアドレスのリソースが再び必要になる日に、よみがえります。「忘れろ」と「作れ」が、同じアドレスに同時にあると、プランが止まります。さらに皮肉なのは、このエラーが、設定の検証(validate)は通過して、プランでだけ出る点です。アドレスを状態と突き合わせる作業は、プランの段階の仕事だからです。CIがvalidateだけを回していると、この問題を検知できません。
2つ目は、組織の分割です。チームが分かれるとき、一方の持ち分をまるごと引き渡す必要がありますが、removedのfromには、モジュールのアドレスも指定できるため、モジュール1つを一度に手放せます。ただし、受け取る側が、その実体を自分の状態に取り込む作業は別で、プロバイダーがそのリソースのインポートをサポートしている必要があります。すべてのリソースがそうとは限りません。
3つ目は、所有者が不在の期間です。手放した時点から、受け取る側が取り込むまで、その実体は、どのコードも管理していません。その間、誰もそれに触れないようにするには、引き渡す作業を、ドキュメントとスケジュールで包む必要があります。ツールがやってくれることではありません。
4つ目は、取り戻せるかどうかです。状態から外したものを、再びコードで管理するには、インポート(import)を行う必要がありますが、プロバイダーがそのリソースのインポートを実装していなければ、方法がありません。このラボのファイルリソースが、まさにそのケースです。そのため、手放す前に、「これは元に戻せる判断か」を一度確認しておくほうが安全です。元に戻せないなら、コピーを残すか、引き渡す側と受け取る側が、同じ時刻に作業する必要があります。
次のラボですること
/root/tfa-removedで、引き継いだファイル1つをremovedで状態からだけ外し、実体が残ることを確認します。このバージョンのremovedが何を受け取るかを、直接尋ねて表に書き、movedで名前を変えて、識別子が維持されることを、ステップ1のコピーと比べ、忘れろという宣言と作れという宣言が重なったときのエラーを受け取ったあと、-replaceとtaintで1つだけ作り直し、最後に、モジュール1つをまるごと手放します。