コンテンツにスキップ

tfstate ファイルの分割

はじめに

本サイトにつきまして、【IT技術の知見】はじめに - 俺の技術ノート をご認識のほど宜しくお願いいたします。


01. tfstate ファイルの分割について


02. ローカル/リモートモジュールのディレクトリ構成

ここから先の話は遊びみたいなもんです👶🏻

ローカルモジュールとリモートモジュールは、”汎用的に使用できる resource ブロックや data ブロックのセット” である。

これらは、モジュールがローカルリポジトリまたはリモートリポジトリのいずれにあるかの違いしかない。

そのため、このディレクトリ構成はローカル / リモートモジュールの両方に適用できる。

ローカルモジュールは、リポジトリ内で汎用的に再利用するユースケースに限って作成するべきである。

そのため、ローカルモジュールは以下のようにする。

  • そもそもローカルモジュールを制限使用にする
  • ローカルモジュールは自前リモートモジュール化する
  • 公式リモートモジュールを使用する

のほうがよい。

ローカル/リモートモジュールのディレクトリ構成について、tfstate ファイルは粒度に関係ないため、これといった目安はないが、参考として今までに観測したことのある例をあげた。


依存先 AWS リソース別

依存先の多い AWS リソースは、依存先の AWS リソース別にローカルモジュールを分割する。

依存先 AWS リソース別の分割方法は、Terraform の公式リモートモジュールに一番多い構成である。

ローカルモジュールの場合

ただ前述の通り、ローカルモジュールの使用するかどうかは考え直したほうがよい。

aws-repository/
└── modules/ # ローカルモジュール
    └── eks/ # EKS
        ├── auto_scaling/ # AutoScaling
        │   ├── main.tf
        │   ├── outputs.tf
        │   └── variables.tf
        │
        ├── iam/ # IAM ロール
        │   ├── main.tf
        │   ├── outputs.tf
        │   └── variables.tf
        │
        ├── kubernetes/ # Kubernetes リソース (例:RoleBinding、StorageClass など)
        │   ├── main.tf
        │   ├── outputs.tf
        │   └── variables.tf
        │
        ├── launch_template/ # 起動テンプレート
        │   ├── main.tf
        │   ├── outputs.tf
        │   └── variables.tf
        │
        ├── security_group/ # セキュリティグループ
        │   ├── main.tf
        │   ├── outputs.tf
        │   └── variables.tf
        │
        └── node_group/ # Node グループ
            ├── main.tf
            ├── outputs.tf
            └── variables.tf

リモートモジュールの場合

aws-remote-repository/
└── eks/ # EKS
    ├── auto_scaling/ # AutoScaling
    │   ├── main.tf
    │   ├── outputs.tf
    │   └── variables.tf
    │
    ├── iam/ # IAM ロール
    │   ├── main.tf
    │   ├── outputs.tf
    │   └── variables.tf
    │
    ├── kubernetes/ # Kubernetes リソース (例:RoleBinding、StorageClass など)
    │   ├── main.tf
    │   ├── outputs.tf
    │   └── variables.tf
    │
    ├── launch_template/ # 起動テンプレート
    │   ├── main.tf
    │   ├── outputs.tf
    │   └── variables.tf
    │
    ├── security_group/ # セキュリティグループ
    │   ├── main.tf
    │   ├── outputs.tf
    │   └── variables.tf
    │
    └── node_group/ # Node グループ
        ├── main.tf
        ├── outputs.tf
        └── variables.tf


リソース別

最上層は、AWS リソースで分割する。

またスクリプトを使用する AWS リソース (例:Lambda) では、そのソースコードをモジュール下で管理する。

ローカルモジュールの場合

ただ前述の通り、ローカルモジュールの使用するかどうかは考え直したほうがよい。

aws-repository/
└── modules/ # ローカルモジュール
    ├── acm/ # AWS Certificate Manager
    ├── alb/ # ALB
    ├── lambda/ # Lambda
    │   ├── foo_function_src/ # とある関数のソースコード
    ...

リモートモジュールの場合

aws-remote-repository/
├── acm/ # AWS Certificate Manager
├── alb/ # ALB
├── lambda/ # Lambda
│   ├── foo_function_src/ # とある関数のソースコード
    ...


リージョン別

AWS リソースのプロビジョニング先のリージョン別にローカルモジュールを分割する。

例えば、AWS Certificate Manager は同じリージョンの AWS リソースにしかアタッチできない制約があるため、AWS リソースによっては複数リージョン必要になる。

ローカルモジュールの場合

ただ前述の通り、ローカルモジュールの使用するかどうかは考え直したほうがよい。

aws-repository/
└── modules/ # ローカルモジュール
    └── acm/ # AWS Certificate Manager
        ├── ap-northeast-1/ # 東京リージョン
        └── us-east-1/      # バージニアリージョン

リモートモジュールの場合

aws-remote-repository/
└── acm/ # AWS Certificate Manager
    ├── ap-northeast-1/ # 東京リージョン
    └── us-east-1/      # バージニアリージョン


実行環境別

環境ごとに差分が大きい AWS リソースは、実行環境別にローカルモジュールを分割する。

なお count で条件分岐してもよい

ローカルモジュールの場合

ただ前述の通り、ローカルモジュールの使用するかどうかは考え直したほうがよい。

aws-repository/
└── modules/ # ローカルモジュール
    ├── route53/ # Route53
    │   ├── tes/ # テスト環境
    │   ├── stg/ # ステージング環境
    │   └── prd/ # 本番環境
    │
    ├── ssm/ # AWS Systems Manager
    │   ├── tes/
    │   ├── stg/
    │   └── prd/
    │
    └── waf/ # WAF
        └── alb/
            ├── tes/
            ├── prd/
            └── stg/

リモートモジュールの場合

aws-remote-repository/
├── route53/ # Route53
│   ├── tes/ # テスト環境
│   ├── stg/ # ステージング環境
│   └── prd/ # 本番環境
│
├── ssm/ # AWS Systems Manager
│   ├── tes/
│   ├── stg/
│   └── prd/
│
└── waf/ # WAF
    └── alb/
        ├── tes/
        ├── prd/
        └── stg/


03. モノリスな tfstate ファイルを分割する

モノリスな tfstate ファイルとは、例えば特定の AWS アカウント内の AWS リソースをすべて 1 つの tfstate ファイルで管理している場合である。

AWS リソース値を参照しない関係であれば、これらは別の tfstate ファイルに分割できる。

  1. 既存のバックエンド内に新しいディレクトリを作成し、その配下に tfstate ファイルを新しく作成する。

    ここでは、サブシステムを分割すると仮定する。

    repository/
    ├── foo/
    │   ├── backend.tf # バックエンド内の/foo/terraform.tfstate
    │   ├── provider.tf
    │   ...
    │
    ├── bar/
    │   ├── backend.tf # バックエンド内の/bar/terraform.tfstate
    │   ├── remote_state.tfvars # terraform_remote_state ブロックを使用し、foo の tfstate ファイルから状態を参照する
    │   ├── resource.tf # foo の tfstate ファイルから参照した状態を使用する
    │   ├── provider.tf
    │   ...
    │
    ...
    
    terraform {
      backend "s3" {
        bucket = "foo-tfstate"
        key    = "foo-sub-system/terraform.tfstate"
        region = "ap-northeast-1"
      }
    }
    
  2. bar 側では、foo 側の tfstate ファイルからリソース値を取得しつつ、

    # 分割した異なるfooというtfstateファイルから取得する
    data "terraform_remote_state" "foo" {
      backend = "s3"
    
      config = {
        bucket = "foo-tfstate"
        key    = "foo/terraform.tfstate"
        region = "ap-northeast-1"
      }
    }
    
  3. 新しい tfstate ファイルに、既存のサブシステムの状態をインポートする。

    事前に、バックエンドを新しいサブシステムのtfstateファイルに切り替える。

    $ terraform init -reconfigure -backend-config=foo-sub-backend.tfvars
    $ terraform import
    
  4. サブシステムの tfstate ファイルで差分がないことを確認する。

    $ terraform init -reconfigure -backend-config=foo-sub-backend.tfvars
    $ terraform plan
    
  5. モノリスな tfstate ファイルから、サブシステムの状態を削除する。

    事前に、バックエンドをモノリスなtfstateファイルに切り替える。

    $ terraform init -reconfigure -backend-config=foo-backend.tfvars
    $ terraform state rm <サブシステムの状態>