ロックファイルを一行いじったら init が止まった
目標
依存関係のロックファイルを自分で作り、制約を付けて絞り、削除して作り直し、ハッシュを壊して、元に戻します。initが毎回何を確認するか、なぜこのファイルだけをコミットして、インストールのディレクトリはコミットしないのかを、手で確認します。
なぜ重要なのか
ロックファイルは、読むファイルではなく、チームの契約書です。どのバージョンを選んだか(version)、何を許可したか(constraints)、そのパッケージが、そのときのものと同じか(hashes)の3つがここに書かれ、initは、毎回この3つを確認します。契約書がなければ、どのコマンドもプランを立てられず、チェックサムが食い違えば、インストールがその場で止まります。このファイルをコミットしないチームは、人によって別のバージョンを取得し、そのため、「自分のノートパソコンでは動く」が、プロバイダー単位で生じます。逆に、インストールのディレクトリはコミットしません。プラットフォームごとに違うバイナリなので、リポジトリが膨らみ、initがいつでも作り直してくれるからです。
ステップ
/root/tfb-lock/app/main.tfに、localとrandomの2つのプロバイダーを、バージョンの制約なしで宣言し、random_pet.tag(length 2)と、そのidをnote.txtに書くlocal_file.noteを置いてください。initしたあと、できた.terraform.lock.hclを読んで、/root/tfb-lock/lock-read.txtに、local_version=<값>、random_version=<값>、local_hashes=<local 블록의 h1 해시 줄 수>の3行を書いてください(プレースホルダーは、順にバージョンの値、バージョンの値、localブロックのh1ハッシュの行数です)。/root/tfb-lock/pinned/main.tfを新しく作成して、今度は最初からlocalにversion = "2.9.0"を書き、randomは制約なしにしてください。local_file.fixedでfixed.txtを1つ宣言して、initしてください。そのあと、ロックファイルからプロバイダーごとのconstraintsの値を読んで、/root/tfb-lock/constraints.txtに、local=<값>とrandom=noneの2行を書いてください(プレースホルダーは値です)。/root/tfb-lock/app/.terraform/providers/の下から、実際にインストールされたプロバイダーのパッケージの場所を探して、/root/tfb-lock/installed.txtに、local=<버전>/<플랫폼>とrandom=<버전>/<플랫폼>の2行を書いてください(プレースホルダーは、順にバージョンとプラットフォームです)。/root/tfb-lock/fresh/を作成して、/root/tfb-lock/app/main.tfだけをコピーしてください(ロックファイルと.terraform/は持ってきません)。initなしでtofu planを実行して、エラーの出力を/root/tfb-lock/no-init.txtに保存してください。freshでは、initをしないでください。/root/tfb-lock/badpin/main.tfに、localだけを使い、version = "2.5.0"で固定して、local_file.pinnedを1つ置いてください。initを実行して、失敗の出力を/root/tfb-lock/pin-fail.txtに保存したあと、制約を2.9.0に直して、initが成功するようにしてください。/root/tfb-lock/app/main.tfのlocalに、ここにきてversion = "2.9.0"を付けて、もう一度initしてください。ロックファイルのlocalブロックに、constraints行ができたかを確認して、/root/tfb-lock/stale-lock.txtの1行目に、after_init=<그 값, 없으면 none>を書いてください(プレースホルダーは、その値で、なければnoneです)。そのあと、.terraform.lock.hclを削除して、initの代わりに、tofu providers lock -fs-mirror=/opt/tofu-mirror -platform=linux_amd64で作り直し、その出力を/root/tfb-lock/relock.txtに保存して、stale-lock.txtの2行目に、after_relock=<지금 값>を書いてください(プレースホルダーは現在の値です)。/root/tfb-lock/app/.terraform.lock.hclのlocalのハッシュの1行を、適当な値に書き換えて、.terraform/を削除したあと、initしてください。チェックサムのエラーの出力を/root/tfb-lock/tamper.txtに保存します。そのあと、ロックファイルを削除して、もう一度initして、正しいハッシュに戻してください。/root/tfb-lock/audit.shを作成してください。最初の引数として受け取ったディレクトリの.terraform.lock.hclを読んで、constraints行がないproviderブロックの名前を、1行ずつ出力し、1つでもあれば終了コード1、なければ0で終了する必要があります。/root/tfb-lock/appに実行した結果を/root/tfb-lock/audit-app.txtに、/root/tfb-lock/badpinに実行した結果を/root/tfb-lock/audit-pin.txtに保存して、各ファイルの最後の行に、exit=<종료 코드>を追記してください(プレースホルダーは終了コードです)。
参考
- Podのプロバイダーは、/opt/tofu-mirrorのファイルシステムミラーからだけ来ます。ミラーには、プロバイダーごとにバージョンが1つずつで、プラットフォームはlinux_amd64だけです。
- そのため、他のプラットフォームのハッシュを、レジストリから取得してくる方式は、このPodでは使えません。その代わり、ミラーを指す
-fs-mirrorを使います。 - よくある間違い: ステップ4のfreshディレクトリで、エラーをなくそうとして、initを実行してしまうこと。このステップは、initしていない状態のエラーを残すことが課題です。
- よくある間違い: ステップ7で、誤ったハッシュをそのままにして、-upgradeだけを付けること。バージョンの選択がそのままなので、同じチェックサムの検査にまた引っかかります。
- ステップ6の核心は、initが「直す理由がなければロックファイルを書かない」ということです。-upgradeでも、constraints行はできません。
- Dependency Lock File・tofu init・tofu providers lock・tofu providers・CLI設定ファイル
最初のinitが作った契約書を読む
/root/tfb-lock/app/main.tfに、localとrandomの2つのプロバイダーを、バージョンの制約なしで宣言し、random_pet.tag(length 2)と、そのidをnote.txtに書くlocal_file.noteを置いてください。initしたあと、できた.terraform.lock.hclを読んで、/root/tfb-lock/lock-read.txtに、local_version=<값>、random_version=<값>、local_hashes=<local 블록의 h1 해시 줄 수>の3行を書いてください(プレースホルダーは、順にバージョンの値、バージョンの値、localブロックのh1ハッシュの行数です)。
ロックファイルはHCLで、プロバイダーごとにproviderブロックが1つずつできます。ブロックの中に、version、必要ならconstraints、そしてhashesのリストが入ります。applyは、まだしなくてもかまいません。
制約を書いて始めると、契約書に許可の範囲も一緒に残る
/root/tfb-lock/pinned/main.tfを新しく作成して、今度は最初からlocalにversion = "2.9.0"を書き、randomは制約なしにしてください。local_file.fixedでfixed.txtを1つ宣言して、initしてください。そのあと、ロックファイルからプロバイダーごとのconstraintsの値を読んで、/root/tfb-lock/constraints.txtに、local=<값>とrandom=noneの2行を書いてください(プレースホルダーは値です)。
constraints行は、設定にバージョンの制約を書いたときにだけ、ロックファイルに現れます。制約を書いていないプロバイダーのブロックには、その行がそもそもありません。何を選んだか(version)と、何を許可したか(constraints)は、別の情報です。
ロックファイルが指す実物がどこにあるかを探す
/root/tfb-lock/app/.terraform/providers/の下から、実際にインストールされたプロバイダーのパッケージの場所を探して、/root/tfb-lock/installed.txtに、local=<버전>/<플랫폼>とrandom=<버전>/<플랫폼>の2行を書いてください(プレースホルダーは、順にバージョンとプラットフォームです)。
インストールのパスは、レジストリのアドレス・ネームスペース・名前・バージョン・プラットフォームの順に深くなります。このディレクトリは、initが作り直してくれるのでコミットしませんが、ロックファイルは、人がレビューする必要があるので、コミットします。
契約書がなければ、プランすら立てられない
/root/tfb-lock/fresh/を作成して、/root/tfb-lock/app/main.tfだけをコピーしてください(ロックファイルと.terraform/は持ってきません)。initなしでtofu planを実行して、エラーの出力を/root/tfb-lock/no-init.txtに保存してください。freshでは、initをしないでください。
新しく受け取ったリポジトリで、人が最初に出会うエラーです。メッセージが何をするように言っているのか、なぜプランの段階で止めるのかを考えてみてください。プロバイダーがなければ、プランを立てられません。
ミラーにないバージョンを固定すると、initが拒否する
/root/tfb-lock/badpin/main.tfに、localだけを使い、version = "2.5.0"で固定して、local_file.pinnedを1つ置いてください。initを実行して、失敗の出力を/root/tfb-lock/pin-fail.txtに保存したあと、制約を2.9.0に直して、initが成功するようにしてください。
このPodのプロバイダーは、オフラインのミラーからだけ来ます。ミラーにないバージョンを要求すると、ツールは選べるものがないと言います。実務でも、社内ミラーだけを使う組織で、同じメッセージに出会います。
あとから付けた制約は、契約書に自動では反映されない
/root/tfb-lock/app/main.tfのlocalに、ここにきてversion = "2.9.0"を付けて、もう一度initしてください。ロックファイルのlocalブロックに、constraints行ができたかを確認して、/root/tfb-lock/stale-lock.txtの1行目に、after_init=<그 값, 없으면 none>を書いてください(プレースホルダーは、その値で、なければnoneです)。そのあと、.terraform.lock.hclを削除して、initの代わりに、tofu providers lock -fs-mirror=/opt/tofu-mirror -platform=linux_amd64で作り直し、その出力を/root/tfb-lock/relock.txtに保存して、stale-lock.txtの2行目に、after_relock=<지금 값>を書いてください(プレースホルダーは現在の値です)。
initは、すでに選んだ選択が、依然として制約に合っていれば、選び直さず、そのため、ロックファイルを新しく書くこともしません。許可の範囲を契約書に反映するには、その項目を新しく作らせる必要があります。providers lockは、パッケージをインストールせずに、チェックサムだけを計算して書きます。
ハッシュに手を加えると、インストールが止まる
/root/tfb-lock/app/.terraform.lock.hclのlocalのハッシュの1行を、適当な値に書き換えて、.terraform/を削除したあと、initしてください。チェックサムのエラーの出力を/root/tfb-lock/tamper.txtに保存します。そのあと、ロックファイルを削除して、もう一度initして、正しいハッシュに戻してください。
ロックファイルのハッシュは、パッケージがそのときのものと同じかを確認する仕組みです。手を加えたハッシュでは、どのパッケージも合わないので、インストールが止まります。誤ったハッシュをそのままにして、-upgradeだけを付けても、解決しません。
制約のないプロバイダーを見つけ出す点検を作る
/root/tfb-lock/audit.shを作成してください。最初の引数として受け取ったディレクトリの.terraform.lock.hclを読んで、constraints行がないproviderブロックの名前を、1行ずつ出力し、1つでもあれば終了コード1、なければ0で終了する必要があります。/root/tfb-lock/appに実行した結果を/root/tfb-lock/audit-app.txtに、/root/tfb-lock/badpinに実行した結果を/root/tfb-lock/audit-pin.txtに保存して、各ファイルの最後の行に、exit=<종료 코드>を追記してください(プレースホルダーは終了コードです)。
ロックファイルは、1行ずつ読めばよいです。providerで始まる行が新しいブロックの始まりで、そのあとにconstraints行が出てくるかどうかだけを覚えておけばよいです。awkのENDブロックで、最後のブロックも判定しないと、1つ見逃します。