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

Infrastructure as Code

二つのリポジトリが同じ設定ファイルを互いに戻し合っていた

TT Labで続きを見る

目標

2つの状態が1つのリソースを巡って争う様子を再現して、removedブロックで所有を整理し、すでにある値を、importブロック・設定の生成・CLIのimportで、削除せずに引き取って、プランが空の状態で管理を始めます。

なぜ重要なのか

IaCを導入するときは、白紙から始めません。手で作ったリソースがすでにあり、それをコードに移す間に、見た目だけを真似して書くと、ツールは新しく作って、既存の値を使っていた場所を壊します。そのため、importで先に状態に登録して、プランが空になるまでコードを整えてはじめて、終わりです。逆に、1つのリソースを2つのコードベースが管理すると、エラーが1つも出ないまま互いを元に戻すので、所有を渡すときは、リソースブロックを削除する(=削除)代わりに、状態からだけ外す方法を使う必要があります。

ステップ

  1. /root/iac-own/team-a/main.tfと/root/iac-own/team-b/main.tfに、それぞれlocal_file.confを置いてください。どちらも/root/iac-own/shared/app.confを管理し、内容はowner=team-a、owner=team-bの1行です。各ディレクトリをinitしたあと、team-a、team-b、team-a、team-bの順でapplyして、applyするたびにファイルの内容を/root/iac-own/flip.txtに1行ずつ追記してください。
  2. team-bが所有を手放すことにしました。team-bのリソースブロックを削除して、removed { from = local_file.conf }ブロックを置いてください。team-bでtofu planの出力を/root/iac-own/forget.txtに保存してからapplyして、続けてteam-aをapplyしてください。ファイルは残っている必要があり(team-aの内容)、team-bの状態にはlocal_fileがあってはならず、2つのディレクトリのプランは、どちらもきれいでなければなりません。
  3. /root/iac-own/legacy.envに、手で作ったリソースの記録を書いてください: DB_PASSWORD=Lb7qK2mZx9Wc4Rt8Yp3N、PORT=8123、PORT_RANGE=8000,8999、INSTANCE_ID=6f1c2a4e-3b7d-4c9a-8e2f-1a2b3c4d5e6f、TOKEN=abcDEF123(1行に1つ)。そのあと、/root/iac-own/naive/main.tfに、importなしで、random_password.db(長さ20)、random_integer.port(8000から8999)、random_uuid.instanceを書き、tofu plan -out=/root/iac-own/naive/naive.tfplanで保存だけしてください(適用しません)。
  4. /root/iac-own/adopt/main.tfに、randomプロバイダーの要求と、importブロック3つだけを置いてください。random_password.dbはlegacy.envのパスワード、random_integer.portは<값>,<최소>,<최대>の形式、random_uuid.instanceはUUIDが識別子です(プレースホルダーは、順に値、最小値、最大値です)。リソースブロックは書かずに、tofu plan -generate-config-out=generated.tfで設定を生成してください。プランが3 to import, 0 to add, 0 to change, 0 to destroyになっている必要があります(適用しません)。
  5. generated.tfの3つのリソースをadopt/main.tfに移して、値がnullの行は除き、デフォルト値と同じ引数も除いて、短く整えてください(パスワードの長さ20、ポートの範囲8000・8999は残します)。generated.tfは削除します。プランが3 to import, 0 to add, 0 to change, 0 to destroyになっているかを確認してから、applyしてください。採点ツールは、状態の値がlegacy.envと同じで、そのあとのプランがきれいかを見ます。
  6. legacy.envのTOKENを、random_string.tokenとして取り込んでください。今回は、importブロックを使わずに、/root/iac-own/adopt/token.tfに、リソースブロック(長さ9)を先に置いたあと、tofu importコマンドで状態に登録します。そのあと、プランがきれいでなければなりません。
  7. /root/iac-own/owners.sh <작업디렉터리>...を作成してください。各ディレクトリの状態から、local_file・local_sensitive_fileが管理するファイルパスを絶対パスで集めて、同じパスが2つ以上のディレクトリにあれば、CONFLICT <경로> <디렉터리들(절대 경로, 정렬, 공백 구분)>をパスごとに1行ずつ出力して3、なければOKと0で終了します(プレースホルダーは、順に作業ディレクトリ、パス、絶対パスで並べ替えて空白で区切ったディレクトリの一覧です)。相対パスのfilenameは、その作業ディレクトリを基準に解決します。採点ツールは、team-a・team-b(これでOK)と、自分で作った競合ディレクトリで確認します。

参考

2つのチームが同じファイルを交互に元に戻す

/root/iac-own/team-a/main.tfと/root/iac-own/team-b/main.tfに、それぞれlocal_file.confを置いてください。どちらも/root/iac-own/shared/app.confを管理し、内容はowner=team-a、owner=team-bの1行です。各ディレクトリをinitしたあと、team-a、team-b、team-a、team-bの順でapplyして、applyするたびにファイルの内容を/root/iac-own/flip.txtに1行ずつ追記してください。

2つの状態は、互いの存在を知りません。片方が書くと、もう片方の次のプランには、そのファイルが「外で変更されたもの」(local_fileでは「削除された」)に見えて、適用すると自分の内容に戻します。最後をteam-bで終える理由は、次のステップで、team-bが自分の記録が生きている状態で所有を手放すようにするためです。このような争いは、エラーなしに静かに続きます。

片方が所有を手放す: 削除せずに状態からだけ外す

team-bが所有を手放すことにしました。team-bのリソースブロックを削除して、removed { from = local_file.conf }ブロックを置いてください。team-bでtofu planの出力を/root/iac-own/forget.txtに保存してからapplyして、続けてteam-aをapplyしてください。ファイルは残っている必要があり(team-aの内容)、team-bの状態にはlocal_fileがあってはならず、2つのディレクトリのプランは、どちらもきれいでなければなりません。

リソースブロックだけを削除すると、ツールはそれを削除として計画します。そうするとteam-aが使うファイルを、team-bが削除します。removedブロックは「管理をやめるだけ」という意味なので、実物はそのままにします。プランの出力の文言を読んで、違いを確認してください。

すでにある値を、見た目だけ真似して書くと新しく作られる

/root/iac-own/legacy.envに、手で作ったリソースの記録を書いてください: DB_PASSWORD=Lb7qK2mZx9Wc4Rt8Yp3N、PORT=8123、PORT_RANGE=8000,8999、INSTANCE_ID=6f1c2a4e-3b7d-4c9a-8e2f-1a2b3c4d5e6f、TOKEN=abcDEF123(1行に1つ)。そのあと、/root/iac-own/naive/main.tfに、importなしで、random_password.db(長さ20)、random_integer.port(8000から8999)、random_uuid.instanceを書き、tofu plan -out=/root/iac-own/naive/naive.tfplanで保存だけしてください(適用しません)。

設定の見た目が同じでも、状態に記録がなければ、ツールにとっては「まだないもの」です。適用すると、既存のパスワードとは違う新しい値ができて、その値を使っていた場所がすべて壊れます。プランのPlanの行で、importが0であることを見てください。

importブロックを使い、設定はツールに生成させる

/root/iac-own/adopt/main.tfに、randomプロバイダーの要求と、importブロック3つだけを置いてください。random_password.dbはlegacy.envのパスワード、random_integer.portは<값>,<최소>,<최대>の形式、random_uuid.instanceはUUIDが識別子です(プレースホルダーは、順に値、最小値、最大値です)。リソースブロックは書かずに、tofu plan -generate-config-out=generated.tfで設定を生成してください。プランが3 to import, 0 to add, 0 to change, 0 to destroyになっている必要があります(適用しません)。

リソースごとに、importの識別子の形式が違います。プロバイダーのドキュメントのImportの節を見てください。設定の生成は実験的な機能で、ファイルがすでにあれば、上書きせずにエラーを出します。

生成した設定を整えて、プランが空のまま取り込む

generated.tfの3つのリソースをadopt/main.tfに移して、値がnullの行は除き、デフォルト値と同じ引数も除いて、短く整えてください(パスワードの長さ20、ポートの範囲8000・8999は残します)。generated.tfは削除します。プランが3 to import, 0 to add, 0 to change, 0 to destroyになっているかを確認してから、applyしてください。採点ツールは、状態の値がlegacy.envと同じで、そのあとのプランがきれいかを見ます。

整える途中で、置き換えを強制する引数(例: 範囲の最大値)を変えると、プランが「取り込んだあとに置き換え」に変わります。そのまま適用すると、取り込んだ値がすぐに消えます。Planの行のadd・destroyが0かどうかが、判断の基準です。

ブロックの代わりにコマンドでもう1つ取り込む

legacy.envのTOKENを、random_string.tokenとして取り込んでください。今回は、importブロックを使わずに、/root/iac-own/adopt/token.tfに、リソースブロック(長さ9)を先に置いたあと、tofu importコマンドで状態に登録します。そのあと、プランがきれいでなければなりません。

命令的なimportは、プランなしにすぐ状態を変えます。そのため、先に設定が必要で、レビューするプランが残りません。importブロックを、コードレビューとプランを経由させるようにした理由です。

所有者が2つあるファイルを見つける点検を作る

/root/iac-own/owners.sh <작업디렉터리>...を作成してください。各ディレクトリの状態から、local_file・local_sensitive_fileが管理するファイルパスを絶対パスで集めて、同じパスが2つ以上のディレクトリにあれば、CONFLICT <경로> <디렉터리들(절대 경로, 정렬, 공백 구분)>をパスごとに1行ずつ出力して3、なければOKと0で終了します(プレースホルダーは、順に作業ディレクトリ、パス、絶対パスで並べ替えて空白で区切ったディレクトリの一覧です)。相対パスのfilenameは、その作業ディレクトリを基準に解決します。採点ツールは、team-a・team-b(これでOK)と、自分で作った競合ディレクトリで確認します。

tofu show -jsonのvaluesから、filenameを得ます。同じ名前の相対パスでも、ディレクトリが違えば、別のファイルです。重複だけを選ぶには、sort | uniq -dが便利です。