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

Terraform実戦

子モジュールを作り複数回呼び出す

TT Labで続きを見る

目標

小さな子モジュールを標準の構造で作り、同じモジュールを複数回呼び出してインスタンスを増やし、モジュール内の値を出力として外に取り出す流れを、身につけます。

なぜ重要なのか

モジュールを使う理由を「コードの重複の排除」としてしか教わらないと、すぐに壁にぶつかります。本当の理由は、変更の波及範囲の制限です。実装が1つなら、直す場所も1か所で、環境間の違いは、コードではなく渡す値だけに現れます。そのため、モジュール設計で最も重要な決定は、「何を変数として開放するか」です。開放しすぎると、モジュールが単なるリソースの別名になり、開放が少なすぎると、誰も使えません。もう1つ覚えておくべきことは、モジュールがカプセルだという点です。モジュール内のリソースは、外から直接参照できず、outputからしか出てきません。この制約は面倒に見えますが、おかげで、モジュールの内部を作り変えても、使う側のコードが壊れません。最後に、子モジュールの中にproviderブロックを置かないでください。そのモジュールの呼び出しを、あとでコードから削除できなくなる、元に戻しにくい事故の原因です。

ステップ

  1. /opt/lab/fixtures/terraform/modules-starter/modules/fileboxを/root/tf/modules/modules/fileboxにコピーしてください。そのディレクトリに、main.tf、variables.tf、outputs.tfの3つのファイルがある必要があります。variables.tfにはvariable "dir"とvariable "name"があり、新しく作成するoutputs.tfにはoutput "path"(値はlocal_file.box.filename)を置いてください。モジュール内にprovider "..."ブロックを置いてはいけません。
  2. /root/tf/modules/main.tfにmodule "primary"を宣言し、source = "./modules/filebox"と指定してください。dirには/root/tf/modules/out、nameにはprimary、bodyには任意の文字列を渡します。tofu initのあとtofu applyで/root/tf/modules/out/primary.txtを作成してください。
  3. /root/tf/modules/outputs.tfにルートの出力primary_pathを作成してmodule.primary.pathを出力し、tofu output -jsonの結果を/root/tf/modules/out/outputs.jsonに保存してください。primary_pathの値は/root/tf/modules/out/primary.txtである必要があります。
  4. 同じソースを、module "secondary"としてもう一度呼び出してください。nameはsecondaryとし、bodyはprimaryとは異なる文字列を渡して、/root/tf/modules/out/secondary.txtの内容がprimary.txtと異なるようにします。モジュールのディレクトリをコピーしないでください。/root/tf/modules/modulesの下のディレクトリは、あとで作成するbundleを含めて、2つを超えてはいけません。
  5. tofu state listの結果を/root/tf/modules/out/state-list.txtに保存してください。module.primary.とmodule.secondary.で始まるアドレスがそれぞれある必要があり、ルートにlocal_file.boxというアドレスが別にあってはいけません。
  6. /root/tf/modules/modules/bundle/main.tfを作成し、その中でsource = "../filebox"としてfileboxを2回呼び出してください(例: module "left"、module "right"、名前はbundle-left・bundle-right)。ルートからmodule "bundle"として呼び出して適用すると、状態にmodule.bundle.module.left....の形のアドレスが2つ以上できます。
  7. /root/tf/modules/modules/filebox/variables.tfのname変数にvalidationブロックを追加し、error_messageも一緒に書いてください(例: 小文字・数字・ハイフンのみ許可)。そのあと、どれかの呼び出しのnameに、ルールに違反する値を一時的に入れて、tofu planの出力を標準エラー出力まで含めて/root/tf/modules/out/module-error.txtに保存してください。保存した内容には、検証失敗のメッセージとfileboxのパスが一緒に表示されている必要があります。確認が終わったら、値を元に戻します。
  8. /root/tf/modules/outputs.tfにall_paths出力を追加してください。primary、secondary、bundleの3つのキーを持つマップで、primaryの値は/root/tf/modules/out/primary.txtである必要があります。bundleモジュールにもoutput "paths"を作成して内側の2つのパスを入れ、それをbundleキーに入れてください。最後に、tofu output -jsonをもう一度/root/tf/modules/out/outputs.jsonに保存します。

参考

モジュールを入力・実装・出力の3つのファイルに分ける

/opt/lab/fixtures/terraform/modules-starter/modules/fileboxを/root/tf/modules/modules/fileboxにコピーしてください。そのディレクトリに、main.tf、variables.tf、outputs.tfの3つのファイルがある必要があります。variables.tfにはvariable "dir"とvariable "name"があり、新しく作成するoutputs.tfにはoutput "path"(値はlocal_file.box.filename)を置いてください。モジュール内にprovider "..."ブロックを置いてはいけません。

モジュールは、ただのディレクトリです。慣例として、変数はvariables.tf、リソースはmain.tf、出力する値はoutputs.tfに置きます。子モジュールの中には、providerの設定ブロックを置かないでください。

モジュールを呼び出して適用する

/root/tf/modules/main.tfにmodule "primary"を宣言し、source = "./modules/filebox"と指定してください。dirには/root/tf/modules/out、nameにはprimary、bodyには任意の文字列を渡します。tofu initのあとtofu applyで/root/tf/modules/out/primary.txtを作成してください。

module "이름"ブロックに、sourceと変数の値を入れます(プレースホルダーはモジュールの呼び出し名です)。モジュールを追加したりソースを変更したりしたら、initをもう一度実行する必要があります。

モジュールの出力をルートに引き上げる

/root/tf/modules/outputs.tfにルートの出力primary_pathを作成してmodule.primary.pathを出力し、tofu output -jsonの結果を/root/tf/modules/out/outputs.jsonに保存してください。primary_pathの値は/root/tf/modules/out/primary.txtである必要があります。

モジュール内のリソースは、外から直接参照できません。子のoutputを、ルートのoutputが改めて受け取って初めて、tofu outputに表示されます。

同じモジュールを、異なる入力で2回呼び出す

同じソースを、module "secondary"としてもう一度呼び出してください。nameはsecondaryとし、bodyはprimaryとは異なる文字列を渡して、/root/tf/modules/out/secondary.txtの内容がprimary.txtと異なるようにします。モジュールのディレクトリをコピーしないでください。/root/tf/modules/modulesの下のディレクトリは、あとで作成するbundleを含めて、2つを超えてはいけません。

ディレクトリをコピーすると、コピペの問題に逆戻りします。同じsourceを、名前だけ変えて呼び出し、渡す値を互いに異なるものにしてください。

モジュールに属するリソースのアドレスを確認する

tofu state listの結果を/root/tf/modules/out/state-list.txtに保存してください。module.primary.とmodule.secondary.で始まるアドレスがそれぞれある必要があり、ルートにlocal_file.boxというアドレスが別にあってはいけません。

モジュール内のリソースには、module.<호출이름>.というプレフィックスが付きます(プレースホルダーは呼び出し名です)。状態の一覧を出力して、プレフィックスが実際に付いているかを見てください。

モジュールの中からモジュールを呼び出す

/root/tf/modules/modules/bundle/main.tfを作成し、その中でsource = "../filebox"としてfileboxを2回呼び出してください(例: module "left"、module "right"、名前はbundle-left・bundle-right)。ルートからmodule "bundle"として呼び出して適用すると、状態にmodule.bundle.module.left....の形のアドレスが2つ以上できます。

子モジュールから兄弟のモジュールを呼び出すときは、相対パスを使います。ネストされると、状態アドレスも二重に積み重なります。

モジュールの境界で誤った値を止める

/root/tf/modules/modules/filebox/variables.tfのname変数にvalidationブロックを追加し、error_messageも一緒に書いてください(例: 小文字・数字・ハイフンのみ許可)。そのあと、どれかの呼び出しのnameに、ルールに違反する値を一時的に入れて、tofu planの出力を標準エラー出力まで含めて/root/tf/modules/out/module-error.txtに保存してください。保存した内容には、検証失敗のメッセージとfileboxのパスが一緒に表示されている必要があります。確認が終わったら、値を元に戻します。

variableブロックの中のvalidationは、conditionとerror_messageを一緒に要求します。拒否される値をあえて一度入れて、エラーを自分の目で確認してください。

3つのモジュールの出力を1つのマップにまとめる

/root/tf/modules/outputs.tfにall_paths出力を追加してください。primary、secondary、bundleの3つのキーを持つマップで、primaryの値は/root/tf/modules/out/primary.txtである必要があります。bundleモジュールにもoutput "paths"を作成して内側の2つのパスを入れ、それをbundleキーに入れてください。最後に、tofu output -jsonをもう一度/root/tf/modules/out/outputs.jsonに保存します。

ルートのoutputの値として、オブジェクトを直接作れます。キー名と数が採点基準なので、正確に合わせてください。