一覧CL-14-3 · Infrastructure as Code

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

1
terraform apply -input=false -auto-approve -no-color > apply.log python3 inspect.py state cat app.conf
resources=['local_file.config', 'local_file.manifest']
port=8080
2
printf "port=9000\n" > app.conf terraform plan -refresh-only -input=false -no-color -out=plan.bin > plan.log python3 inspect.py drift
observed_drift=local_file.config delete
planned_changes=0
3
terraform apply -input=false -no-color plan.bin > apply.log python3 inspect.py state cat app.conf
resources=['local_file.manifest']
port=9000
4
terraform plan -input=false -no-color -out=plan.bin > plan.log python3 inspect.py plan
local_file.config create
local_file.manifest no-op
5
terraform apply -input=false -no-color plan.bin > apply.log cat app.conf python3 inspect.py state
port=8080
resources=['local_file.config', 'local_file.manifest']
6
python3 inspect.py lock
concurrent_plan=state_lock_error
holder_released_lock=True
7
printf 'resource "terraform_data" "adopted" {}\n' > adopted.tf python3 inspect.py import terraform state list
imported_address=terraform_data.adopted
id=fixture-existing-id
local_file.config
local_file.manifest
terraform_data.adopted

演習完了