Terraformでのリソース管理の最適化: tfstateファイルの分割と移動手順

Tech

2024.3.5

Topics

はじめに

こんにちは、Shunです。

Terraformを運用する上で、tfファイルが増えたことによる管理工数の増加やAPI実行制限などにより、tfstateファイルの分割を検討されたことはないでしょうか?

この記事では、Terraformを用いたインフラのコード管理で直面することがあるtfstateファイルの分割が必要なケースを想定して、tfstateファイル内のリソースの移動方法と、必要となるTerraformコマンドについて解説します。

想定読者

  • Terraformの運用を行っている方
  • tfstateファイルの分割を考えている方

本記事で紹介する内容

  • tfstateで管理しているリソースをどのように移行するか
  • 移行時に使用するTerraformコマンド

本記事で取り扱わない内容

  • Terraformの基本的な概念解説
  • Terraformの一般的なコマンド説明

実施すること

前提

  • Terraformがセットアップ済みであること
  • tfstateファイルをローカルで管理していること(リモート管理の場合も、手順の追加により対応可能です。)

手順

今回実施する手順は以下です。

  1. 必要なファイルの準備
  2. リソース作成
  3. tfstateファイルから移行対象を切り出す
  4. tfstateファイルへ移行対象を追加する
  5. 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ファイルの取り扱いには細心の注意を払い、十分な検証を行った上で実施することを推奨します。

最後まで読んでいただきありがとうございます!

Shun

好きな言葉は生ビール199円です。日本ビール協会認定1冠、AWS12冠、Google Cloud11冠

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら