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

Terraform/OpenTofu基礎

依存グラフと状態ファイルの解剖

TT Labで続きを見る

目標

参照が依存関係のグラフをどう作るかを、状態ファイルで直接確認し、状態を、人と機械の2つの方式で読んで、メタデータを取り出せるようになります。

なぜ重要なのか

Terraformを数日使うと、「なぜ順序がこうなのか」という疑問が、必ず出てきます。答えはいつもグラフです。ツールは、ファイルに書かれた順序を見ず、どのリソースが、どのリソースの値を使うかだけを見ます。そのため、値を参照すれば順序ができ、値をコピーして書けば順序がなくなります。depends_onは、値としては表に出ない順序を表現する抜け道ですが、習慣になると、グラフが太くなって、実行が遅くなり、再作成が横に広がります。一方、この関係は、状態ファイルにdependenciesとして記録されますが、これが、コードからリソースを削除したあとでも、正しい逆順で削除できる根拠です。状態を手で編集することがなぜ危険かも、ここで理解できます。

ステップ

  1. /root/tf/stateに設定を作成して、初期化してください。名前がseedのrandom_petと、名前がchildのlocal_fileを宣言して、childの内容がrandom_pet.seedの値を参照するようにしてください。childにはdepends_onを使わないでください。適用のあと、状態のlocal_file.childのdependenciesにrandom_pet.seedが入っている必要があります。
  2. 名前がmarkerのlocal_fileを追加して、/root/tf/state/main.tfにdepends_on = [local_file.child]を書いて、順序を固定してください。適用のあと、状態のlocal_file.markerのdependenciesに、local_file.childが見えなければなりません。
  3. 状態に登録されたリソースアドレスの一覧を、/root/tf/state/out/state-list.txtに保存してください。random_pet.seed、local_file.child、local_file.markerの3行が、それぞれまったくその文字列のまま入っている必要があります。
  4. 状態のJSON表現を、/root/tf/state/out/state.jsonに保存してください。.values.root_module.resourcesの下にリソースが3個以上あり、そのうちaddressがlocal_file.childの項目がある必要があります。
  5. /root/tf/state/out/meta.jsonを作成してください。serial、lineage、version、resource_countの4つのキーを持ち、最初の3つは/root/tf/state/terraform.tfstateの値と同じで、resource_countは状態のresources配列の長さと同じでなければなりません。
  6. childが作ったファイルを、Terraformを経由せず、シェルで直接削除したあと、その状態でプランを出力して、/root/tf/state/out/drift-plan.txtに保存してください。出力に、local_file.childを再作成するという内容があり、「変更なし」であってはいけません。
  7. /root/tf/state/.terraform.lock.hclを読んで、そこに固定されているプロバイダーの名前とバージョンを1行にまとめて、/root/tf/state/out/lock-note.txtに保存してください。localという名前と、2.5.3のような3桁のバージョン番号が、どちらも入っている必要があります。
  8. 名前がstage_a、stage_b、stage_cのlocal_fileを3つ追加して、stage_bはstage_aの値を、stage_cはstage_bの値を、参照するようにしてください。適用したあと、/root/tf/state/out/chain.txtに、作られる順序のとおりにlocal_file.stage_a、local_file.stage_b、local_file.stage_cを1行に1つずつ、合計3行で書いてください。

参考

参照だけで依存関係を作る

/root/tf/stateに設定を作成して、初期化してください。名前がseedのrandom_petと、名前がchildのlocal_fileを宣言して、childの内容がrandom_pet.seedの値を参照するようにしてください。childにはdepends_onを使わないでください。適用のあと、状態のlocal_file.childのdependenciesにrandom_pet.seedが入っている必要があります。

他のリソースの属性を式で使えば、それがそのまま順序の宣言です。このステップでは、depends_onを使わずに、状態のdependencies配列が埋まるかどうかで確認してください。

depends_onで順序を固定する

名前がmarkerのlocal_fileを追加して、/root/tf/state/main.tfにdepends_on = [local_file.child]を書いて、順序を固定してください。適用のあと、状態のlocal_file.markerのdependenciesに、local_file.childが見えなければなりません。

値は使わないのに、順序だけが必要なときに使う引数があります。値はリソースアドレスのリストで、引用符で囲みません。

状態のアドレス一覧を取り出す

状態に登録されたリソースアドレスの一覧を、/root/tf/state/out/state-list.txtに保存してください。random_pet.seed、local_file.child、local_file.markerの3行が、それぞれまったくその文字列のまま入っている必要があります。

状態に登録されたアドレスだけを、1行ずつ表示するサブコマンドがあります。ファイルには、アドレス以外の装飾が入ってはいけません。

状態をJSONで取り出す

状態のJSON表現を、/root/tf/state/out/state.jsonに保存してください。.values.root_module.resourcesの下にリソースが3個以上あり、そのうちaddressがlocal_file.childの項目がある必要があります。

人が読む出力と、機械が読む出力は、別のオプションです。JSONの中で、リソースの一覧がどのパスにあるかを、jqでたどってみてください。

状態のメタデータを記録する

/root/tf/state/out/meta.jsonを作成してください。serial、lineage、version、resource_countの4つのキーを持ち、最初の3つは/root/tf/state/terraform.tfstateの値と同じで、resource_countは状態のresources配列の長さと同じでなければなりません。

4つのキーが必要です。値を目でコピーせず、状態ファイルから直接取り出して組み立てれば、間違えることはありません。リソースの個数は、配列の長さです。

手で削除したファイルがプランで捕捉されるかを見る

childが作ったファイルを、Terraformを経由せず、シェルで直接削除したあと、その状態でプランを出力して、/root/tf/state/out/drift-plan.txtに保存してください。出力に、local_file.childを再作成するという内容があり、「変更なし」であってはいけません。

コードはそのままにして、成果物だけをなくすと、照会の段階で差が明らかになります。再び適用する前に、プランの出力を先に保存してください。

ロックファイルからプロバイダーのバージョンを読む

/root/tf/state/.terraform.lock.hclを読んで、そこに固定されているプロバイダーの名前とバージョンを1行にまとめて、/root/tf/state/out/lock-note.txtに保存してください。localという名前と、2.5.3のような3桁のバージョン番号が、どちらも入っている必要があります。

ロックファイルには、プロバイダーのブロックと、確定したバージョン、そしてハッシュがあります。ハッシュが何を保証するのかを考えながら、1行にまとめてください。

3段階の依存の連鎖を作って、順序を記録する

名前がstage_a、stage_b、stage_cのlocal_fileを3つ追加して、stage_bはstage_aの値を、stage_cはstage_bの値を、参照するようにしてください。適用したあと、/root/tf/state/out/chain.txtに、作られる順序のとおりにlocal_file.stage_a、local_file.stage_b、local_file.stage_cを1行に1つずつ、合計3行で書いてください。

前のステップの結果を、次のステップが参照するようにつなげれば、連鎖になります。記録する順序は、コードに書いた順序ではなく、作られる順序です。