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

Terraform/OpenTofu基礎

読むだけのブロックが状態に残った

TT Labで続きを見る

目標

dataブロックがresourceと何が違うかを、状態・プラン・破壊の3つの場面で直接確認します。読み取りがいつ起きるか、何を所有しないか、元のものがなかったり、変わったりしたらどうなるかを、OpenTofuで1つずつ起こしてみます。

なぜ重要なのか

設定ファイルで、dataブロックはresourceと同じくらいよく出てきますが、2つを同じものとして読むと、事故が静かに起きます。dataは、対象を作りも削除もしません。destroyを回しても元のものはそのまま残り、そのため、他のチームが作ったものを読んで使う設定が安全になります。その代わり、dataは、状態に保存された値を信じず、プランのたびにもう一度読みます。元のものが変われば、それはドリフトではなく入力が変わったことで、下流が丸ごと置き換えられることがあります。読み取る対象の名前がまだ決まっていなかったり、depends_onがかかっていたりすると、読み取りが適用時点に先送りされますが、このとき、プランには値が丸ごと「不明」と出て、レビューが難しくなります。この4つを手で体験しておけば、他人の設定を読むときに、dataブロックで目が止まるようになります。

ステップ

  1. /root/tfb-data/base/seed.txtにalphaを1行、直接作成して、同じディレクトリのmain.tfに、そのファイルを読むdata "local_file" "seed"と、その内容をcopy.txtに書くresource "local_file" "copy"を置いてください。init・applyして、プランがきれいでなければなりません。
  2. /root/tfb-data/base/terraform.tfstateを開いて、modeがdataの項目とmanagedの項目のアドレスを、それぞれ探し、/root/tfb-data/shape.txtにdata=<그 주소>とmanaged=<그 주소>の2行を書いてください(プレースホルダーはそのアドレスです)。アドレスは、data.local_file.seedのように、modeの接頭辞まで含んだ形です。
  3. /root/tfb-data/own/に同じ形の設定を置いて、seed.txtはownedを1行にしてください。init・applyでcopy.txtを作ったあと、tofu destroy -auto-approveを実行して、その出力を/root/tfb-data/own-destroy.txtに保存してください。もう一度applyはしません。
  4. /root/tfb-data/deferred/main.tfに、random_pet.name(length 2)、その名前が入ったmade-<이름>.txtを書くlocal_file.made、そのファイルを読むdata.local_file.back、読み取った値をecho.txtに書くlocal_file.echoを置いてください(プレースホルダーは名前です)。initしたあと、planの出力を/root/tfb-data/deferred-plan.txtに保存して、applyしてください。
  5. /root/tfb-data/gate/ready.txtをreadyの1行で先に作っておいてください。同じディレクトリのmain.tfに、null_resource.prepare(triggers v = "1")、depends_on = [null_resource.prepare]を付けたdata.local_file.ready、読み取った値をmirror.txtに書くlocal_file.mirrorを置いて、initしてください。planの出力を/root/tfb-data/gate-plan.txtに保存したあと、applyしてください。
  6. /root/tfb-data/missing/main.tfに、存在しないファイルabsent.txtを読むdata.local_file.absentと、その内容を出力する出力absentを置いて、initしてください。planを実行して、エラーの出力を/root/tfb-data/missing-plan.txtに保存してください。コマンドが失敗してもかまいません。absent.txtは作らないでください。
  7. /root/tfb-data/tfdata/main.tfに、terraform_data.note(input "v1")と、そのoutputを出力する出力noteを置いて、init・applyしてください。そのあと、inputを"v2"に変更して、planの出力を/root/tfb-data/tfdata-plan.txtに保存したあと、applyしてください。最後に、/root/tfb-data/mode-compare.txtに、terraform_data=<tfdata 상태에서 읽은 mode>とlocal_file_seed=<base 상태에서 읽은 mode>の2行を書いてください(プレースホルダーは、順にtfdataの状態から読み取ったmode、baseの状態から読み取ったmodeです)。
  8. /root/tfb-data/base/seed.txtをbetaの1行に変更して、/root/tfb-data/baseでplanを実行し、出力を/root/tfb-data/data-change.txtに保存したあと、applyしてください。プランがなぜ置き換え(replace)として出るのかを確認し、最後に、プランが再びきれいになっている必要があります。

参考

すでにあるファイルをdataで読む

/root/tfb-data/base/seed.txtにalphaを1行、直接作成して、同じディレクトリのmain.tfに、そのファイルを読むdata "local_file" "seed"と、その内容をcopy.txtに書くresource "local_file" "copy"を置いてください。init・applyして、プランがきれいでなければなりません。

dataブロックは、作らずに、読み取るだけです。読み取った値は、data.<타입>.<이름>.<속성>で参照します(プレースホルダーは、順にタイプ、名前、属性です)。localプロバイダーのfileデータソースは、content属性にファイルの内容を入れてくれます。

状態で、読み取ったものと作ったものを分ける

/root/tfb-data/base/terraform.tfstateを開いて、modeがdataの項目とmanagedの項目のアドレスを、それぞれ探し、/root/tfb-data/shape.txtにdata=<그 주소>とmanaged=<그 주소>の2行を書いてください(プレースホルダーはそのアドレスです)。アドレスは、data.local_file.seedのように、modeの接頭辞まで含んだ形です。

状態JSONの各項目には、mode・type・nameがあります。modeがdataなら、アドレスの前にdata.が付き、managedなら付きません。tofu state listの出力と比べてみてください。

destroyしても、読み取っただけの元のものは残る

/root/tfb-data/own/に同じ形の設定を置いて、seed.txtはownedを1行にしてください。init・applyでcopy.txtを作ったあと、tofu destroy -auto-approveを実行して、その出力を/root/tfb-data/own-destroy.txtに保存してください。もう一度applyはしません。

destroyは、状態が所有するものだけを削除します。dataで読み取っただけのファイルは、状態に記録は残っても、所有物ではありません。destroyの直前の状態は、terraform.tfstate.backupとして残ります。

読み取る対象がまだなければ、読み取りがapplyに先送りされる

/root/tfb-data/deferred/main.tfに、random_pet.name(length 2)、その名前が入ったmade-<이름>.txtを書くlocal_file.made、そのファイルを読むdata.local_file.back、読み取った値をecho.txtに書くlocal_file.echoを置いてください(プレースホルダーは名前です)。initしたあと、planの出力を/root/tfb-data/deferred-plan.txtに保存して、applyしてください。

データソースの引数がplanの時点で不明な値なら、読み取りを先送りします。プランの出力で、そのデータソースの行がどう書かれているかを、そのまま読んでみてください。

depends_onを付けると、すでにあるファイルもplanのときに読めない

/root/tfb-data/gate/ready.txtをreadyの1行で先に作っておいてください。同じディレクトリのmain.tfに、null_resource.prepare(triggers v = "1")、depends_on = [null_resource.prepare]を付けたdata.local_file.ready、読み取った値をmirror.txtに書くlocal_file.mirrorを置いて、initしてください。planの出力を/root/tfb-data/gate-plan.txtに保存したあと、applyしてください。

元のものがすでにあっても、depends_onがあれば、ツールはその依存が終わる前には読みません。ステップ1のプランの出力と比べると、違いが1行で明らかになります。

元のものがなければ、プラン自体が失敗する

/root/tfb-data/missing/main.tfに、存在しないファイルabsent.txtを読むdata.local_file.absentと、その内容を出力する出力absentを置いて、initしてください。planを実行して、エラーの出力を/root/tfb-data/missing-plan.txtに保存してください。コマンドが失敗してもかまいません。absent.txtは作らないでください。

データソースの読み取りは、プランの段階で起きます。そのため、読み取れなければ、適用まで進めず、プランが止まります。エラーメッセージのタイトルと原因の行を、そのまま保存してください。

terraform_dataはdataではなくmanagedである

/root/tfb-data/tfdata/main.tfに、terraform_data.note(input "v1")と、そのoutputを出力する出力noteを置いて、init・applyしてください。そのあと、inputを"v2"に変更して、planの出力を/root/tfb-data/tfdata-plan.txtに保存したあと、applyしてください。最後に、/root/tfb-data/mode-compare.txtに、terraform_data=<tfdata 상태에서 읽은 mode>とlocal_file_seed=<base 상태에서 읽은 mode>の2行を書いてください(プレースホルダーは、順にtfdataの状態から読み取ったmode、baseの状態から読み取ったmodeです)。

名前だけ見るとデータソースのようですが、状態のmodeを見れば答えが出ます。プランの出力の動作を表す語も、データソースとは違います。データソースはread、こちらはライフサイクルがあるリソースです。

元のものが変わると、ドリフトではなく入力が変わったことになる

/root/tfb-data/base/seed.txtをbetaの1行に変更して、/root/tfb-data/baseでplanを実行し、出力を/root/tfb-data/data-change.txtに保存したあと、applyしてください。プランがなぜ置き換え(replace)として出るのかを確認し、最後に、プランが再びきれいになっている必要があります。

データソースは、状態に保存された値を信じず、プランのたびにもう一度読みます。そのため、元のものが変われば、状態が食い違ったのではなく、下流のリソースの入力が変わったものとして捕捉されます。local_fileのcontentは、その場での更新ができない属性です。