Terraformの状態管理と既存リソースの取り込み
実体の修復、stateの更新、同時操作の排他、既存IDの登録がそれぞれ何を変えるか説明します。
説明
Terraformの宣言、state、実体は別々に存在します。管理外の変更が入ると三者の対応が崩れます。refresh-onlyは観測した状態をstateへ反映し、通常のapplyは宣言に合わせて実体を変更します。
local_fileで作った設定を手で書き換え、検出される差分を調べます。stateだけを更新した後に宣言の値へ戻し、同時planのロック拒否を確認します。最後に組込みterraform_dataでimportによるアドレス登録を確認します。
実体の修復、stateの更新、同時操作の排他、既存IDの登録がそれぞれ何を変えるか説明します。
1一致した状態を作る
初期定義の2ファイルを作り、stateと実ファイルを確認します。
terraform apply専用ファイルの初期状態を作る -input=false -auto-approve -no-color > apply.log
python3 inspect.py statestateの管理対象を読む
cat app.conf初期の実体を読むstateにはconfigとmanifest、実ファイルにはport=8080があります。以降はこの対応を変更します。
2Terraformを通さず変更する
app.confだけを手で9000へ変えます。宣言とstateは直接編集しません。
printf管理外の経路で実ファイルを変更する "port=9000\n" > app.conf
terraform plan -refresh-only実体の変化をstateへ反映する計画を作る -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py driftproviderが観測した差分を読むlocal_file providerは内容ハッシュが変わったファイルを、管理していた元のファイルが消失したものとして検出します。一般のクラウド資源が常にdeleteで表されるわけではありません。
3観測結果だけをstateへ反映する
refresh-onlyの計画を適用します。宣言の8080を実ファイルへ書き戻す操作ではありません。
terraform applyrefresh-onlyの計画を適用する -input=false -no-color plan.bin > apply.log
python3 inspect.py state更新後のstateを読む
cat app.conf実ファイルが修復されていないことを読むconfigがstateから外れ、実ファイルは9000のままです。stateの更新と実体の修復を区別できました。
4宣言へ戻す計画を作る
通常のplanでは、宣言のconfigを再作成する計画になります。
terraform plan宣言へ合わせる変更を計画する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan再作成対象を読むconfigがcreate、manifestはno-opです。元の宣言に必要なファイルを再び管理下へ作ります。
5実体を修復する
計画を適用して、実ファイルとstateを読みます。
terraform apply再作成計画を適用する -input=false -no-color plan.bin > apply.log
cat app.conf修復した実体を読む
python3 inspect.py statestateとの対応を確認するport=8080へ戻り、2資源がstateへ登録されています。観測だけだった前の操作と、実体の修復を比較できます。
6同じstateへの並行操作を拒否する
inspect.pyがローカルstateファイルの排他ロックを保持したまま、別プロセスのterraform planを実行します。
python3 inspect.py lock実ファイルロック中のplan失敗を確認する別のplanはstate_lock_errorで停止し、保持側がロックを解放します。これはlocal backendの実ファイルロックの検査で、別backendの方式を表すものではありません。
7importでアドレスとIDを結び付ける
terraform_dataは値をstateで管理する組込み資源です。ここでは外部ファイルを操作せず、指定IDを既存のものとして管理アドレスへ登録します。
printfimport先の管理アドレスを宣言する 'resource "terraform_data" "adopted" {}\n' > adopted.tf
python3 inspect.py import実際のterraform importを実行する
terraform state list追加された管理対象を確認するterraform_data.adoptedにfixture-existing-idが登録されます。この例が示すのはstateへの対応付けです。外部資源を扱うproviderでは、対応するimport IDの形式と取得処理が必要になります。
まとめ
refresh-onlyは観測結果をstateへ反映し、実体を宣言へ修復する操作とは異なります。
stateロックは同じ保存先への競合操作を防ぎます。
importは資源アドレスと既存IDの対応を登録します。
操作履歴と解説を振り返れます。
Terraform 1.17.0 / hashicorp/local 2.5.3 / local backend
terraform apply -input=false -auto-approve -no-color > apply.log
python3 inspect.py state
cat app.confresources=['local_file.config', 'local_file.manifest'] port=8080
printf "port=9000\n" > app.conf
terraform plan -refresh-only -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py driftobserved_drift=local_file.config delete planned_changes=0
terraform apply -input=false -no-color plan.bin > apply.log
python3 inspect.py state
cat app.confresources=['local_file.manifest'] port=9000
terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py planlocal_file.config create local_file.manifest no-op
terraform apply -input=false -no-color plan.bin > apply.log
cat app.conf
python3 inspect.py stateport=8080 resources=['local_file.config', 'local_file.manifest']
python3 inspect.py lockconcurrent_plan=state_lock_error holder_released_lock=True
printf 'resource "terraform_data" "adopted" {}\n' > adopted.tf
python3 inspect.py import
terraform state listimported_address=terraform_data.adopted id=fixture-existing-id local_file.config local_file.manifest terraform_data.adopted
演習完了