Terraformでのリソース管理の最適化: tfstateファイルの分割と移動手順
はじめに
こんにちは、Shunです。
Terraformを運用する上で、tfファイルが増えたことによる管理工数の増加やAPI実行制限などにより、tfstateファイルの分割を検討されたことはないでしょうか?
この記事では、Terraformを用いたインフラのコード管理で直面することがあるtfstateファイルの分割が必要なケースを想定して、tfstateファイル内のリソースの移動方法と、必要となるTerraformコマンドについて解説します。
想定読者
- Terraformの運用を行っている方
- tfstateファイルの分割を考えている方
本記事で紹介する内容
- tfstateで管理しているリソースをどのように移行するか
- 移行時に使用するTerraformコマンド
本記事で取り扱わない内容
- Terraformの基本的な概念解説
- Terraformの一般的なコマンド説明
実施すること
前提
- Terraformがセットアップ済みであること
- tfstateファイルをローカルで管理していること(リモート管理の場合も、手順の追加により対応可能です。)
手順
今回実施する手順は以下です。
- 必要なファイルの準備
- リソース作成
- tfstateファイルから移行対象を切り出す
- tfstateファイルへ移行対象を追加する
- tfファイルの変更
実際の作業
1. 必要なファイルの準備
ディレクトリ構造は以下の通りです。
terraform
├── from
│ └── from.tf
└── to
└── to.tf
/from/from.tf
resource "terraform_data" "from1" {}
resource "terraform_data" "from2" {}
/to/to.tf
resource "terraform_data" "to1" {}
今回の移行では、バックエンドやプロバイダの指定は行いません。
また、terraform_dataは、terraform1.4.0以降で使用できるリソースブロックです。
terraform1.4.0より前は、null_resourceとして用いられていました。
詳細は以下のドキュメントを参照してください。
2. リソース作成
それぞれのディレクトリでterraform_dataリソースを作成します。
# リソースを作成します。 $ terraform init $ terraform apply -auto-approve # 管理対象を確認します。 $ terraform state list terraform_data.from1 terraform_data.from2
toディレクトリでも同様の作業を行います。
applyが成功すると、以下のようにtfstateファイルが作成されます。
terraform
├── from
│ ├── from.tf
│ └── terraform.tfstate
└── to
├── to.tf
└── terraform.tfstate
3. tfstateファイルから移行対象を切り出す
fromディレクトリで管理されているterraform_data.from2を切り出します。
現在の/from/terraform.tfstateは以下の状態です。
{
"version": 4,
"terraform_version": "1.7.0",
"serial": 3,
"lineage": "77ad1c22-6635-1bba-09ce-98227d5b6287",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "terraform_data",
"name": "from1",
"provider": "provider[\"terraform.io/builtin/terraform\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "6d642543-2a09-f4dd-d379-64d6ea0acc80",
"input": null,
"output": null,
"triggers_replace": null
},
"sensitive_attributes": []
}
]
},
{
"mode": "managed",
"type": "terraform_data",
"name": "from2",
"provider": "provider[\"terraform.io/builtin/terraform\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "36e3de90-4adc-35d2-57a9-ef83362cb06d",
"input": null,
"output": null,
"triggers_replace": null
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
}
以下のコマンドを実行してterraform_data.from2を切り出します。
$ terraform state mv -state-out=from.tfstate terraform_data.from2 terraform_data.from2 Move "terraform_data.from2" to "terraform_data.from2" Successfully moved 1 object(s).
terraform state mvコマンドの詳細を知りたい方は以下をご覧ください。
これにより、/from/terraform.tfstateからterraform_data.from2が管理対象から外れます。
$ terraform state list terraform_data.from1
4. tfstateファイルへ移行対象を追加する
次に、toディレクトリで/from/from.tfstateに格納されたterraform_data.from2を/to/terraform.tfstateへ移行します。
まず、現在のバックエンドの状態をローカルにコピーします。
$ terraform state pull > to.tfstate
terraform state pullコマンドの詳細を知りたい方は以下をご覧ください。
続いて、/from/from.tfstateのリソースを/to/to.tfstateへマージします。
# リソースの識別子をfrom2→to2へ変更します。 $ terraform state mv -state=../from/from.tfstate -state-out=to.tfstate terraform_data.from2 terraform_data.to2 Move "terraform_data.from2" to "terraform_data.to2" Successfully moved 1 object(s).
これだけでは、先ほどローカルへコピーした/to/to.tfstateへ移行対象が移動しただけです。
$ terraform state list terraform_data.to1
現在の/to/to.tfstateは以下の状態です。
{
"version": 4,
"terraform_version": "1.7.0",
"serial": 1,
"lineage": "a0c59a83-dfd9-d9e1-d2d9-d6083494c06e",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "terraform_data",
"name": "to1",
"provider": "provider[\"terraform.io/builtin/terraform\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "ced38e32-7f20-4456-2758-7091fd424aac",
"input": null,
"output": null,
"triggers_replace": null
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
}
terraform state pullでバックエンドの状態をローカルにコピーし、terraform state pushで変更をバックエンドに適用します。
$ terraform state push to.tfstate
terraform state pushコマンドの詳細を知りたい方は以下をご覧ください。
これで、to/to.tfstateで追加されたterraform_data.to2が/to/terraform.tfstateにプッシュされます。
$ terraform state list terraform_data.to1 terraform_data.to2
/to/terraform.tfstateでも管理対象に追加されていることが確認できます。
{
"version": 4,
"terraform_version": "1.7.0",
"serial": 2,
"lineage": "a0c59a83-dfd9-d9e1-d2d9-d6083494c06e",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "terraform_data",
"name": "to1",
"provider": "provider[\"terraform.io/builtin/terraform\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "ced38e32-7f20-4456-2758-7091fd424aac",
"input": null,
"output": null,
"triggers_replace": null
},
"sensitive_attributes": []
}
]
},
{
"mode": "managed",
"type": "terraform_data",
"name": "to2",
"provider": "provider[\"terraform.io/builtin/terraform\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "dfb49bcd-3694-e2eb-7e77-3144712ef403",
"input": null,
"output": null,
"triggers_replace": null
},
"sensitive_attributes": []
}
]
}
],
"check_results": null
}
5. tfファイルの変更
最後に、管理対象の移動に伴って、tfファイル内のresourceブロックを更新します。
これにより、terraform planを実行した際に差分が生じないようにします。
/from/from.tf と /to/to.tf を以下のように更新します。
/from/from.tf
resource "terraform_data" "from1" {}
# resource "terraform_data" "from2" {}
/to/to.tf
resource "terraform_data" "to1" {}
resource "terraform_data" "to2" {}
まとめ
この記事では、tfstateファイルのリソース移動方法について解説しました。
初めは単一のディレクトリでの管理の方が簡単ですが、ファイル数の増加やAPI制限などにより、分割が必要となる場合があります。
その際は、本記事で紹介した手順を参考にしてください。
ただし、不適切な操作によりファイルが破損した場合、復旧が困難になることやインフラの状態と実際のリソースの状態が不一致になる可能性があるため、tfstateファイルの取り扱いには細心の注意を払い、十分な検証を行った上で実施することを推奨します。
最後まで読んでいただきありがとうございます!
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitterGoogle Cloud Partner Top Engineer 2025、2024 AWS All Cert、ビール検定1冠
Recommends
こちらもおすすめ
-
AWS CodePipelineでTerraformパイプラインを実装する
2024.3.28
-
事例でわかる!AWS利活用の勘所~移行と運用最適化~ セミナー開催レポート
2019.8.19
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16
