state fileをローカルファイルに書き出す
source側
terraform state pull > source.tfstate
destination側
terraform state pull > destination.tfstate
新しいdirectoryにtfstateファイルを移動
mkdir merge-state
mv /path/to/source.tfstate merge-state
mv /path/to/destination.tfstate merge-state
cd merge-state
resourcesのリストファイルを作成
terraform state list -state=destination.tfstate > destination-resources.txt
terraform state list -state=source.tfstate > source-resources.txt
中身はこんな感じ↓
data.aws_ecr_lifecycle_policy_document.foo_policy
data.aws_iam_policy_document.foo_policy
aws_ecr_lifecycle_policy.foo_policy
aws_ecr_repository.foo
aws_route53_record.about
...
一応、SourceとDestinationのResourceの数も数えておきます
wc -l source-resources.txt
107 source-resources.txt
wc -l destination-resources.txt
22 destination-resources.txt
state を移動
-
stateには
module.aaa.aws_s3_bucket["aaa"]
のようにdoublequotesが入っている可能性があるので、escapeする必要あり。 -
また、以下のコマンドだと、
xargs: command line cannot be assembled, too long
というエラーが出たりするのでlineごとにloopで回した (xargsあまり使いこなせていないので)
cat source-resources.txt | xargs -I {} bash -c 'terraform state mv -state=source.tfstate -state-out=destination.tfstate "{}" "source_module.{}"'
while IFS= read -r resource; do
terraform state mv -state=source.tfstate -state-out=destination.tfstate "$resource" "$resource"
done < source-resources.txt
terraform state list -state=source.tfstate | wc -l
0
terraform state list -state=destination.tfstate | wc -l
129
107 (source resources before) + 22 (destination resources before) = 0 (source resources after) + 129 (destination resources after) で一致しています
コードの移動
対象となるsourceのterraformコードをDestination側に移します
destination 側で確認
destinationのterraform codeのあるdirectoryに移動して destination-after.tfstate
に変更後のstate fileを移動します。
cp /path/merge-state/destination.tfstate destination-after.tfstate
backendの設定をremoteからlocalに変えます。
- backend "s3" {
- bucket = "your-terraform"
- key = "aws/naka/terraform.tfstate"
- }
+ backend "local" {
+ path = "destination-after.tfstate"
+ }
remote stateはいじらずに、initしたいので -reconfigure
Optionをつけてinitします。
terraform init -reconfigure
planをしてみます。
terraform plan
No changeになればcodeとstateが一致しています。
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.
No changes これで、 source から destinationへの移行が完了しました!
これで一致しない場合は何がおかしいのかを確認して、もう一度merge-stateに戻ってstateのマージに間違いがないかやり直します。もし状況がわからなくなってしまった場合には、backendの変更をrevertして terraform init -reconfigure
すれば、始める前の状態に戻ることができます。
stateをremoteに戻す
無事に、stateのマージができたので、最後にlocal fileにあるstateをremoteに反映します。
今はlocalのbackendになっているので、destination側のbackendを元々のremote backendに戻します。
+ backend "s3" {
+ bucket = "your-terraform"
+ key = "aws/naka/terraform.tfstate"
+ }
- backend "local" {
- path = "destination-after.tfstate"
- }
terraform init
すると以下のように聞かれます。
terraform init
Initializing the backend...
Initializing modules...
╷
│ Error: Backend configuration changed
│
│ A change in the backend configuration has been detected, which may require migrating existing state.
│
│ If you wish to attempt automatic migration of the state, use "terraform init -migrate-state".
│ If you wish to store the current configuration with no changes to the state, use "terraform init -reconfigure".
automatic migration of the stateをしたいので、-migrate-state
をつけて実行します。
terraform init -migrate-state
そうすると以下のように local -> s3 (remote) にコピーするかどうかが聞かれます。
terraform init -migrate-state
Initializing the backend...
Terraform detected that the backend type changed from "local" to "s3".
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "local" backend to the
newly configured "s3" backend. An existing non-empty state already exists in
the new backend. The two states have been saved to temporary files that will be
removed after responding to this query.
Previous (type "local"): /var/folders/20/jnrp85t51hd23cjk51_btywh0000gp/T/terraform4131371062/1-local.tfstate
New (type "s3"): /var/folders/20/jnrp85t51hd23cjk51_btywh0000gp/T/terraform4131371062/2-s3.tfstate
Do you want to overwrite the state in the new backend with the previous state?
Enter "yes" to copy and "no" to start with the existing state in the newly
configured "s3" backend.
Enter a value:
/var/folders/20/jnrp85t51hd23cjk51_btywh0000gp/T/terraform4131371062/1-local.tfstate
一応中身を軽く確認して (行数やversionをチェックする程度) yes
と答えます。
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing modules...
Initializing provider plugins...
...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
そうするとlocal stateをs3(remote)のbackendにコピーしてくれます。
最後にこの状態でterraform plan
を実行して No changes
がでればOKです
完全に完了です。
No changes. Your infrastructure matches the configuration.
あとは、Source側のコードとCIを削除して、PushしてCI上でもNo changesとなるのをみて、Mergeをして終わりです。