[Terraform] 一部モジュールのstateファイルを分割し、別ディレクトリに移動させる

stateファイルのお引越し
2022.01.06

ちゃだいん(@chazuke4649)です。

Terraformにて、「このモジュールだけライフサイクルが違う(ほとんど変更しない)」とか「このモジュールだけリソースが多すぎてplan/applyが重すぎる」等々の理由により、stateファイルを分けたい場合があると思います。

今回一部のモジュールだけ別のstateファイルで管理するために、別のディレクトリに移す機会があったのでその流れを紹介します。

やってみた

作業前のディレクトリ構造は以下の通りです。

作業前

% tree
.
├── master #移動元
│   ├── scp.tf
│   ├── aft.tf
│   ├── backend.tf
├── master_aft #移動先
│   └── backend.tf

上記のmaster内のaft.tfに書かれている module "aft" {}だけを、master_aftディレクトリに移動させます。

作業の流れ

コマンドレベルになっていますが、作業の流れは以下の通りです。

  • 1)移動元:Moduleのstateをローカルの別ファイルに移動させる
    • state list
    • state pull
    • state mv
  • 2)移動先:stateファイルを取り込む
    • moduleのtfファイルをコピペ
    • temp.tfstateをコピペ
    • init
    • plan
    • init --reconfigure
    • state push
  • 3)後片付け

それでは早速やっていきます。

1)移動元:Moduleのstateをローカルの別ファイルに移動させる

まずは移動元のディレクトリで作業をするので、masterディレクトリに移動します。

state list

リソースの一覧を取得し、移動させたいリソースを把握します。

% terraform state list > statelist.txt

state pull

stateファイルのバックアップとして、ローカルのにリモートのstateファイルをコピーします。そのファイルをbackup.tfstateとします。

% terraform state pull > backup.tfstate

state mv

リモートのstateファイルから、移動させたいmoduleのstateのみ、ローカルへ移します。そのファイルをtemp.tfstateとします。

% terraform state mv -state-out=temp.tfstate module.aft module.aft
...
# 中略
...
Successfully moved 14 object(s).

実は今回地味に一番言いたかったことなのですがterraform state mvコマンドにてモジュールを丸ごと移す場合は、詳細なリソースアドレスを指定する必要がなく、モジュール名(今回でいうmodule.aft)までで良いという点が発見でした。

例えばこれがモジュールでなく通常のリソースだと、リソース1つ1つを以降元と移動先のリソースアドレスを以下の通り指定する必要があります。(ここを正規表現でいい感じにまとめる方法があるのかはわかってません)

% terraform state mv -state-out=temp.tfstate aws_ec2_transit_gateway.main aws_ec2_transit_gateway.main

   
 

ちょっと脱線しましたが、これによってaftモジュールのstateファイルはtemp.tfstateファイルに移されました。なので、aft.tfファイル上のmoduleのコードをコメントアウトしてplanすると、"No changes."となるはずです。(これをstate mvせずに行うと、もちろんコード上削除されたことになるので、Terraformはコードと合わせるために、aftモジュールによって作成された実際のリソースも削除しようとします)

2)移動先:stateファイルを取り込む

それでは移動先のmaster_aftディレクトリに移動します。

moduleのtfファイルをコピペ

移動元のaft.tfを移動先のディレクトリに複製します。(オリジナルは作業完了後に削除してください)

temp.tfstateをコピペ

移動元のtemp.tfstateを移動先のディレクトリに複製します。(オリジナルは作業完了後に削除してください)

init

backend.tfは移動元のbackend.tfを複製したものです。今回はstateファイルの保存先にS3を使用しています。この段階では、terraformブロック内の backend s3 {} ブロックは一旦コメントアウトしておきます。

それではinitし、moduleをローカルの.terraformに取り込みます。

% terraform init

plan

複製したaft.tfとローカルのtemp.tfstateを使用してplanを行い、モジュールのコードとstateファイル、実環境のリソースが一致し、"No changes."となるかどうか確認します。 planコマンドでは、明示的にローカルのtemp.tfstateを指定します。

% terraform plan -state=temp.tfstate

init --reconfigure

planが通ればもう安心。 backend.tfのbackend s3周りの記述のコメントアウトを外し、stateファイルの保存先をS3に設定します。この時、移動元のS3と全く同じ保存先にならないように注意します。

% terraform init --reconfigure

これによって、リモートのstateファイル保存先としてのS3が設定されました。

state push

S3へローカルのstateファイルをpushします。

% terraform state push temp.tfstate

基本的にはこれで完了です。

3)念のための確認と後片付け

移動後のstate listと移動前のstate listの差分がないかどうか確認する

そのままですが、移動前のstate listにて取得したリソース一覧と、移動後それぞれのディレクトリのリソース一覧の合計が同じかどうか確認します。

問題なければ、完了です。

作業後のディレクトリ構造は以下のような感じになります。

% tree
.
├── master
│   ├── scp.tf
│   ├── backend.tf
│   ├── backup.tfstate #あとで削除
│   ├── temp.tfstate #あとで削除
│   ├── statelist.txt #あとで削除
│   ├── statelist2.txt #あとで削除
├── master_aft
│   ├── aft.tf
│   ├── temp.tfstate #あとで削除
│   ├── statelist.txt #あとで削除
│   └── backend.tf

これらリストとバックアップで取得したbackup.tfstate、すでにリモートにpush済みのローカルのtemp.tfstateを削除すれば後片付け終了です。

作業は以上です。

参考URL

Command: state mv | Terraform by HashiCorp

Terraformのリソースを別のtfstateファイルに移動する - karakaram-blog

Terraformのstate移動とrename