🌀
TerraformのStateマージやってみた
このブログで知ること
- How to Merge State Files で記載されていることの簡易な具体例
このブログでは知れないこと
- 大量リソースのStateマージ
やってみる
想定する初期状況と構成
- Terraformバージョンは 1.10.0 以上である(DDBロックテーブルが不要)
- 以下のようにそれぞれ fuga と hoge ディレクトリ内で別々にS3でリモートState管理されている
- マージされたState管理するS3バケットは作成されている
- fuga と hoge のdynamodbのリソースIDが一意である(それぞれのリソースIDで重複するものはない。なお、もしもリソースIDが重複する場合は、Rename and move a resource を参考にIDを更新すると良い。統合する際に、
moved
ブロックを削除する。)
.
├── fuga
│ ├── fuga_dynamodb.tf
│ └── terraform.tf
└── hoge
├── hoge_dynamodb.tf
└── terraform.tf
対応手順
- 各リモートStateを各ディレクトリのローカルに取得する(Obtain both state files)
- 1のバックアップを作成する (Backup creation)
- terraform初期化していない新しいディレクトリを作成し、マージしたいStateとリソースファイルを配置する (Create a new, empty directory)
- マージの被対象と対象先を確認する (Identify which state will be the end state)
- Stateで管理されているリソースを確認する (View Resources)
- リソース・モジュールのステートを移行する (Move top-level resources and top-level modules)
- 移行元ステートと移行先ステートファイルを確認する (View source state and destination state files)
- 対象先のステートファイルの
serial
の値を1増やす (increment the "serial" value by1
) - マージされたステートファイルをアップロードする (Upload the new, merged state to its final destination)
- リモートステートのリソースを確認 (Review)
完了後の構成
.
├── fuga
│ ├── fuga_dynamodb.tf
│ ├── source.tfstate.cp # バックアップ
│ └── terraform.tf
├── hoge
│ ├── destination.tfstate.cp # バックアップ
│ ├── hoge_dynamodb.tf
│ └── terraform.tf
└── merge
├── destination-resources.txt
├── destination.tfstate
├── destination.tfstate.xxxxxx.backup
├── fuga_dynamodb.tf # マージ非対称のリソース
├── hoge_dynamodb.tf # マージ対象先のリソース
├── source-resources.txt
├── source.tfstate
├── source.tfstate.xxxxxx.backup
└── terraform.tf
1. 各リモートStateを各ディレクトリのローカルに取得する
# fuga
terraform state pull > source.tfstate
# hoge
terraform state pull > destination.tfstate
2. 1のバックアップを作成する
# fuga
cp source.tfstate source.tfstate.cp
# hoge
cp destination.tfstate destination.tfstate.cp
3. 新しいディレクトリを作成し、マージしたいStateとリソースファイルを配置する
└── merge
├── destination.tfstate
├── fuga_dynamodb.tf # マージ非対称のリソース
├── hoge_dynamodb.tf # マージ対象先のリソース
└── source.tfstate
4. マージ被対象と対象先を確認する
今回は、fuga から hoge にマージさせます。
5. Stateで管理されているリソースを確認する
# merge
terraform state list -state=source.tfstate > source-resources.txt
# aws_dynamodb_table.fuga
terraform state list -state=destination.tfstate > destination-resources.txt
# aws_dynamodb_table.hoge
6. リソース・モジュールのステートを移行する
ローカルで実行する場合は、 -state=source.tfstate -state-out=destination.tfstate
をオプションで付けろということなのでその通りにする。
# manual
terraform state mv [options] SOURCE DESTINATION
# 今回のケース
terraform state mv -state=source.tfstate -state-out=destination.tfstate aws_dynamodb_table.fuga aws_dynamodb_table.fuga
7. 移行元ステートと移行先ステートファイルを確認する
# merge
terraform state list -state=source.tfstate
# 何も表示されない
# merge
terraform state list -state=destination.tfstate
# aws_dynamodb_table.fuga
# aws_dynamodb_table.hoge
serial
の値を1増やす
8. 対象先のステートファイルの 今回だと destination.tfstate
の serial
の値を増やします。
9. マージされたステートファイルをアップロードする
mergeディレクトリに (別のリモートState管理のバケットを指定した) terraform.tf
配置して以下を実行する。
# merge
terraform init
terraform state push destination.tfstate
10. リモートステートのリソースを確認
# merge
terraform state list
# aws_dynamodb_table.fuga
# aws_dynamodb_table.hoge
terraform plan
# No changes. Your infrastructure matches the configuration.
# Terraform has compared your real infrastructure against your configuration
# and found no differences, so no changes are needed.
思ったこと
- 6の手順において、リソースが何十とあるとしんどくなってくると思うけど、
terraform state list -state=source.tfstate > source-resources.txt
で出力されたリソース名を読み込んで mv させる、例えば以下のようなスクリプトを実行すれば大量リソースがあってもそこまで工数かけずにいけるのだろうか。
#!/bin/bash
# 引数チェック
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <state-file> <resource-file>"
echo "Example: $0 hoge.tf source-resources.txt"
exit 1
fi
STATE_FILE="$1"
RESOURCE_FILE="$2"
# ファイル存在チェック
if [ ! -f "$RESOURCE_FILE" ]; then
echo "Error: Resource file '$RESOURCE_FILE' not found"
exit 1
fi
if [ ! -f "$STATE_FILE" ]; then
echo "Error: State file '$STATE_FILE' not found"
exit 1
fi
# ファイルから行を読み取ってループ
while IFS= read -r resource; do
# 空行スキップ
if [ -z "$resource" ]; then
continue
fi
echo "Moving resource: $resource"
terraform state mv \
-state="$STATE_FILE" \
-state-out=destination.tfstate \
"$resource" "$resource"
done < "$RESOURCE_FILE"
- 大量のリソースがある場合は、terraform state fileのマージ のように数で確認するのが良さそうですね。
Discussion