好きな技術を布教したい 😗

〜 沼のまわりに餌をまく 〜

【Terraform🧑🏻‍🚀】tfstateファイルの分割パターンとディレクトリ構成への適用


この記事から得られる知識

この記事を読むと、以下を "完全に理解" できます✌️

  • Terraformのtfstateファイルを分割する目的と、オススメの分割パターンについて (★)
  • Terraformのリポジトリやリモートバックエンドのディレクトリ構成の設計について

記事のざっくりした内容は、以下のスライドからキャッチアップできちゃいます!



01. はじめに


どうも、Mitchell Hashimoto です。

terraform_icon.png


さて最近の業務で、全プロダクトの技術基盤開発チームに携わっており、チームが使っているTerraform🧑🏻‍🚀のリポジトリをリプレイスする作業を担当しました。

このリポジトリでは単一のtfstateファイルが状態を持ち過ぎている課題を抱えていたため、課題に合った適切な分割パターンでリプレイスしました。

今回は、この時に整理した分割パターン (AWS向け) を記事で解説しました。

もちろん、GoogleCloudやAzureでも読み換えていただければ、同じように適用できます。

知る限りの分割パターンを記載したところ、情報量がエグいことになってしまったため、気になる分割パターンだけ拾って帰っていただけるとハッピーです🙏

それでは、もりもり布教していきます😗

記事中のこのボックスは、補足情報を記載しています。

飛ばしていただいても大丈夫ですが、読んでもらえるとより理解が深まるはずです👍


02. なぜ tfstate ファイルを分割するのか

分割していない場合

そもそも、なぜtfstateファイルを分割する必要があるのでしょうか。

tfstateファイルを分割しなかったと仮定します。

様々なインフラコンポーネントを単一のtfstateファイルで状態を持つ場合、1回のterraformコマンド全てのコンポーネントの状態を操作できて楽です。

ただし、複数の作業ブランチがある状況だと煩わしいことが起こります。

各作業ブランチでインフラコンポーネントの状態を変更しかけていると、他の作業ブランチから影響を受け、terraformコマンドでtargetオプションが必要になってしまいます。

他にも、terraformコマンドの完了に時間がかかりすぎるといった問題も起こるかもしれません。

単一のtfstateファイルで管理するコンポーネントが多くなるほど、これらの問題は顕著になります。

terraform_architecture_same-tfstate

分割している場合

その一方で、tfstateファイルをいい感じに分割したと仮定します。

各作業ブランチでは、まるで暗黙的にtargetオプションがついたように、他の作業ブランチから影響を受けずにterraformコマンドを実行できます。

よって、各tfstateファイルを操作できる管理者は互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate

分割しなくていい場合

運用ルールや開発者人数が理由で作業が衝突せず、targetオプションが必要ない状況であれば、tfstateファイルは分割しなくてもよいでしょう。

tfstateファイルを分割するメリットが少ないです🙅🏻‍

terraform_architecture_tiny-tfstate


03. tfstate ファイルの分割

分割の境界

それでは、tfstateファイルの分割の境界はどのようにして見つければよいのでしょうか。

これを見つけるコツは、できるだけ相互に依存しないインフラリソースの関係 に注目することだと考えています。

ここでいう依存とは、tfstateファイルが他のtfstateファイルの状態を使用することです。

状態をほとんど使用し合わないインフラリソース同士を、異なるtfstateファイルで管理します。

異なるtfstateファイルで管理できる分割パターンについては後述します。


▶ 『依存』という用語について

ソフトウェアアーキテクチャの文脈では、他を使用することを『依存』と表現します。

そのため便宜上、tfstateファイルでも同じ用語で表現することにしました。

@tmknom さんが述べている通り、Terraformをよりよく設計するためには、『ソフトウェアの基礎知識』が必要です👍


状態の依存関係図

依存関係図とは

分割したtfstateファイル間の状態の依存関係を表現した図です。

プロバイダーのアカウントの状態をtfstateファイルで管理していることを想像してみてください。

terraform_architecture_different-tfstate_independent_diagram


似たものとしてterraform graphコマンドによるグラフがありますが、これはインフラリソース間の依存関係図です。

tfstateファイル間で相互に依存関係があるからといって、個別のインフラリソース間で循環参照が起こってしまうというわけではないです。

続いて、依存関係がある場合と無い場合で、どのような依存関係図になるかを紹介していきます。

依存関係の表現

▼ 依存関係の表現記法

tfstateファイル間で状態の依存関係がある場合、これを図で表現すると分割の状況がわかりやすくなります。

『依存』は、---> (波線矢印) で表現することとします。

設定値の参照数が少ないほどよいです。

依存関係がある場合については、後述します。


▶ 『依存』の波線矢印について

ソフトウェアアーキテクチャの文脈では、『依存』を---> (波線矢印) で表現します。

そのため便宜上、tfstateファイルでも同じ記号で表現することにしました👍

▼ 依存関係がない場合

例えば、AWSリソースからなるプロダクトをいくつかのtfstateファイル (foo-tfstatebar-tfstate) に分割したと仮定します。

ここで仮定した状況では、

tfstate ファイル間に依存関係はない

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

tfstateファイル間に依存関係がない状況がベストです。

terraform_architecture_different-tfstate_independent

▼ 依存関係がある場合

同様に分割したと仮定します。

ここで仮定した状況では、

foo-tfstate ➡︎ bar-tfstate の方向に依存している

とします。

そのため、---> (波線矢印) を使用して、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_dependent


04. tfstate ファイルに基づくその他の設計

リポジトリ 🐱 の設計

リポジトリ分割

ここまでで、tfstateファイル分割について簡単に紹介しました。

リポジトリの分割は、tfstateファイル分割に基づいて設計しましょう。

異なるリポジトリtfstateファイルをおいた方がよい場合については、分割パターン で説明しています。

🐱 foo-repository/
├── backend.tf # fooコンポーネントの状態を持つ tfstate ファイルを指定する
...
🐱 bar-repository/
├── backend.tf # barコンポーネントの状態を持つ tfstate ファイルを指定する
...

ディレクトリ 📂 構成

リポジトリ内のディレクトリ構成も、tfstateファイル分割に基づいて設計しましょう。

率直に言うと、Terraformのディレクトリ構成のパターンは無数にあります。

そのため、基準なしにディレクトリ構成を考えると何でもあり になってしまいます。

その一方で、tfstateファイル分割に基づいて設計することにより、明確なディレクトリ構成パターン として抽出可能になります。

🐱 repository/
├── 📂 foo/
│    ├── backend.tf # fooコンポーネントの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 bar/
      ├── backend.tf # barコンポーネントの状態を持つ tfstate ファイルを指定する
      ...


▶ ローカルモジュールのディレクトリ構成の設計について

Terraformには、そのリポジトリ内だけでブロック (例:resourcedata) のセットを使い回すことを目的とした、ローカルモジュールがあります。

今回、これのディレクトリ構成は設計に含めていません。

混同しやすいのですが、tfstateファイル分割に基づくディレクトリ構成とローカルモジュール内のそれは、全く別のテーマとして切り離して考えることができます👍


リモートバックエンド 🪣 の設計

リモートバックエンド分割

本記事では、リモートバックエンドとしてAWS S3バケットを使用することを想定しています。

リモートバックエンドの分割は、tfstateファイル分割に基づいて設計しましょう。

異なるリモートバックエンドにtfstateファイルをおいた方がよい場合については、分割パターン で説明しています。

🪣 foo-bucket/
│
└── terraform.tfstate # fooコンポーネントの状態を持つ
🪣 bar-bucket/
│
└── terraform.tfstate # barコンポーネントの状態を持つ

ディレクトリ構成

もし、リモートバックエンドをtfstateファイル分割に基づいて分割しなかったとします。

その場合は、代わりにリモートバックエンド内のディレクトリ構成をtfstateファイル分割に基づいて設計しましょう。

🪣 bucket/
├── 📂 foo/
│    └── terraform.tfstate # fooコンポーネントの状態を持つ
│
└── 📂 bar/
      └── terraform.tfstate # barコンポーネントの状態を持つ


05. 状態の依存関係の定義方法

terraform_remote_stateブロックの場合

terraform_remote_stateブロックによる依存

terraform_remote_stateブロックには、以下のメリデメがあります。

アーキテクチャ
特性
メリット ⭕️ デメリット ×
可読性 - terraform_remote_stateブロックに加えてoutputブロックも実装が必要であり、outputブロックは依存先のAWSリソースが一見してわかりにくい。
拡張性 依存先のAWSリソースに関わらず、同じterraform_remote_stateブロックを使い回せる。 -
保守性 - 依存先と依存元の間でTerraformのバージョンに差がありすぎると、tfstateファイル間で互換性がなくなり、terraform_remote_stateブロックの処理が失敗する。

本記事では、 terraform_remote_state ブロックを使用して、状態の依存関係を定義 していきます。

tfstateファイルが他のtfstateファイルに依存する方法として、後述のAWSリソース別dataブロックがあります。

状態の依存関係図

例えば、AWSリソースからなるプロダクトをいくつかのtfstateファイル (foo-tfstatebar-tfstate) に分割したと仮定します。

ここで仮定した状況では、bar-tfstateファイルはVPCの状態を持っており、

foo-tfstate ファイルは bar-tfstate ファイルに依存している

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_dependent_terraform-remote-state

リポジトリディレクトリ構成

tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

ディレクトリの設計方法は、分割パターン で説明しています。

🐱 repository/
├── 📂 foo/
│    ├── backend.tf # fooコンポーネントの状態を持つ tfstate ファイルを指定する
│    ├── remote_state.tf # terraform_remote_stateブロックを使用し、bar-tfstate ファイルに依存する
│    ├── provider.tf
│    ...
│
└── 📂 bar/
      ├── backend.tf # barコンポーネントの状態を持つ tfstate ファイルを指定する
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── provider.tf
      ...

foo-tfstateファイルがbar-tfstateファイルに依存するために必要な実装は、以下の通りになります。

resource "example" "foo" {

  # fooリソースは、bar-tfstate ファイルのVPCに依存する
  vpc_id = data.terraform_remote_state.bar.outputs.bar_vpc_id

  ...
}

data "terraform_remote_state" "bar" {

 backend = "s3"

  config = {
    bucket = "tfstate"
    key    = "bar/terraform.tfstate"
    region = "ap-northeast-1"
  }
}
# VPCの状態は、bar-tfstate ファイルで持つ
output "bar_vpc_id" {
  value = aws_vpc.bar.id
}

resource "aws_vpc" "bar" {
  ...
}

リモートバックエンドのディレクトリ構成

tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

🪣 bucket/
├── 📂 foo
│    └── terraform.tfstate # fooコンポーネントの状態を持つ
│
└── 📂 bar
      └── terraform.tfstate # barコンポーネントの状態を持つ


AWSリソース別dataブロックの場合

AWSリソース別dataブロックによる依存

AWSリソース別dataブロックには、以下のメリデメがあります。

アーキテクチャ
特性
メリット ⭕️ デメリット ×
可読性 依存先のAWSリソースがわかりやすい。 -
拡張性 - 依存先のAWSリソース別dataブロックが必要である。
保守性 依存先と依存元の間でTerraformのバージョンに差があっても、tfstateファイル間で直接的に依存するわけではないため、バージョン差の影響を受けない。 -

今回は使用しませんが、依存関係の他の定義方法として、AWSリソース別dataブロックがあります。

これは、tfstateファイルが自身以外 (例:コンソール画面、他のtfstateファイル) で作成されたAWSリソースの状態に依存するために使用できます。

terraform_remote_stateブロックとは異なり、直接的にはtfstateファイルに依存しません。

AWSリソース別dataブロックの場合は、実際のAWSリソースの状態に依存することにより、間接的にAWSリソースのtfstateファイルに依存することになります。

状態の依存関係図

例えば、AWSリソース別dataブロックも同様にして、AWSリソースからなるプロダクトをいくつかのtfstateファイル (foo-tfstatebar-tfstate) に分割したと仮定します。

ここで仮定した状況では、bar-tfstateファイルはVPCの状態を持っており、

foo-tfstate ファイルは bar-tfstate ファイルに依存している

とします。

想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_dependent_data

リポジトリディレクトリ構成

ディレクトリ構成は、tfstateファイル分割に基づいて、以下の通りになります。

🐱 repository/
├── 📂 foo/
│    ├── backend.tf # fooコンポーネントの状態を持つ tfstate ファイルを指定する
│    ├── data.tf # dataブロックを使用し、bar-tfstate ファイルに依存する
│    ├── provider.tf
│    ...
│
└── 📂 bar/
      ├── backend.tf # barコンポーネントの状態を持つ tfstate ファイルを指定する
      ├── provider.tf
      ...

foo-tfstateファイルがbar-tfstateファイルに依存するために必要な実装は、以下の通りになります。

# fooリソースの状態は、foo-tfstate ファイルで持つ
resource "example" "foo" {

  # fooリソースは、bar-tfstate ファイルのVPCに依存する
  vpc_id     = data.aws_vpc.bar.id
}

# VPCの状態は、bar-tfstate ファイルで持つ
data "aws_vpc" "bar" {

  filter {
    name   = "tag:Name"
    values = ["<bar-tfstateが持つVPCの名前>"]
  }
}

リモートバックエンドのディレクトリ構成

tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

🪣 bucket/
├── 📂 foo
│    └── terraform.tfstate # fooコンポーネントの状態を持つ
│
└── 📂 bar
      └── terraform.tfstate # barコンポーネントの状態を持つ


06. tfstate ファイルの分割パターン

オススメな設計の一覧

前述の通り、tfstateファイルの分割の境界は、『他の状態にできるだけ依存しないリソースの関係』から見つけることができます。

分割しすぎると terraform_remote_stateブロック地獄 になるため、細かすぎず粗すぎない適切な境界を見つけていきましょう。

今回は、私が考える分割パターンをいくつか紹介します。

全てが実用的なパターンというわけでないため、オススメするものを ★ としています。

推奨

任意
tfstate
分割パターン
大分類
tfstate
分割パターン
小分類
オススメ 対応する
リポジトリ構成 🐱
対応する
リモートバックエンド構成 🪣
推奨 上層 プロバイダーのアカウント別 ★★★ リポジトリ自体
または上層ディレクト
リモートバックエンド自体
または上層ディレクト
下層実行環境別 ★★★ 下層ディレクト 下層ディレクト
任意 中間層 運用チーム責務範囲別 ★★ 中間層ディレクト 中間層ディレクト
プロダクトのサブコンポーネント ★★
運用チーム責務範囲別
×
プロダクトのサブコンポーネント
(組み合わせ)
同じテナント内のプロダクト別
AWSリソースの種類グループ別
AWSリソースの状態の変更頻度グループ別


大分類 (上層/下層/中間層) とディレクトリ構成の関係

リポジトリの場合

記事内のここ で、リポジトリ内のディレクトリ構成はtfstateファイル分割に基づいて設計するべき、という説明をしました。

tfstateファイルの分割パターンは、上層/下層/中間層 の層に大別できます。

これらの層は、以下の通りリポジトリ自体・ディレクトリ構成の設計方法に影響します。

# リポジトリ自体を分割する場合
🐱 上層/
├── 📂 中間層/
│    ├── 📂 下層/
│    │    ├── backend.tfvars # 分割された tfstate ファイルを指定する
│    │    ...
│    │
...
# リポジトリ内のディレクトリを分割する場合
🐱 リポジトリ/
├── 📂 上層/
│    ├── 📂 中間層/
│    │    ├── 📂 下層/
│    │    │    ├── backend.tfvars # 分割された tfstate ファイルを指定する
│    │    │    ...
│    │    │
...

リモートバックエンドの場合

記事内のここ で、リモートバックエンドのディレクトリ構成についても言及しました。

これらの層は、以下の通りリモートバックエンド自体・ディレクトリ構成の設計方法に影響します。

# リモートバックエンド自体を分割する場合
🪣 上層/
├── 📂 中間層/
│    ├── 📂 下層/
│    │    └── terraform.tfstate # 分割された状態を持つ
│    │
│    │
...
# リモートバックエンド内のディレクトリを分割する場合
🪣 bucket/
├── 📂 上層/
│    ├── 📂 中間層/
│    │    ├── 📂 下層/
│    │    │    └── terraform.tfstate # 分割された状態を持つ
│    │    │
│    │    │
...


07. 上層の分割 (推奨)

上層の分割について

上層の分割は 推奨 です。

Terraformに携わる管理者の数が少なくても採用した方がよいです。

tfstateファイルをパターンに応じて分割し、これに基づいてディレクトリ・リモートバックエンドも設計しましょう。


プロバイダーのアカウント別 - ★★★

この分割方法について

上層分割の中でも、基本的な方法の1つです。

プロバイダーのアカウント別にtfstateファイルを分割し、上層もこれに基づいて設計します。

この分割方法により、各プロバイダーの管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_provider-accounts_branch


▶ おすすめ度について

一部のプロバイダーは、分割できず、他のプロバイダーと同じtfstateファイルで状態を管理せざるを得ない場合があります。

例えば、Kubernetesのプロバイダーは、EKSと同じtfstateファイルで管理した方がよいです👍

【プロバイダーアカウント別】状態の依存関係図

例えば、以下のプロバイダーを使用したい状況と仮定します。

  • 主要プロバイダー (AWS)
  • アプリ/インフラ監視プロバイダー (Datadog)
  • ジョブ監視プロバイダー (Healthchecks)
  • インシデント管理プロバイダー (PagerDuty)

ここで仮定した状況では、

各プロバイダーの tfstate ファイル間で状態が相互に依存している

とします。

AWSリソース間の相互依存ではないため、循環参照は起こりません。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_provider-accounts

【プロバイダーアカウント別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

プロバイダーアカウント別に分割したtfstateファイルを、異なるリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🐱 aws-repository/
├── backend.tf # AWSの状態を持つ tfstate ファイルを指定する
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
...
🐱 datadog-repository/
├── backend.tf # Datadogの状態を持つ tfstate ファイルを指定する
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
...
🐱 healthchecks-repository/
├── backend.tf # Healthchecksの状態を持つ tfstate ファイルを指定する
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
...
🐱 pagerduty-repository/
├── backend.tf # PagerDutyの状態を持つ tfstate ファイルを指定する
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
...

▼ 同じリポジトリの場合

プロバイダーアカウント別に分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🐱 repository/
├── 📂 aws/
│    ├── backend.tf # AWSの状態を持つ tfstate ファイルを指定する
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ...
│
├── 📂 datadog/
│    ├── backend.tf # Datadogの状態を持つ tfstate ファイルを指定する
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ...
│
├── 📂 healthchecks/
│    ├── backend.tf # Healthchecksの状態を持つ tfstate ファイルを指定する
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ...
│
└── 📂 pagerduty/
      ├── backend.tf # PagerDutyの状態を持つ tfstate ファイルを指定する
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── remote_state.tf # terraform_remote_state ブロックを使用する
      ├── provider.tf
      ...


【プロバイダーアカウント別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

プロバイダーアカウント別に分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🪣 aws-bucket/
│
└── terraform.tfstate # AWSの状態を持つ
🪣 datadog-bucket/
│
└── terraform.tfstate # Datadogの状態を持つ
🪣 healthchecks-bucket/
│
└── terraform.tfstate # Healthchecksの状態を持つ
🪣 pagerduty-bucket/
│
└── terraform.tfstate # PagerDutyの状態を持つ

▼ 同じリモートバックエンドの場合

プロバイダーアカウント別に分割したtfstateファイルを、同じリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🪣 bucket/
├── 📂 aws
│    └── terraform.tfstate # AWSの状態を持つ
│
├── 📂 datadog
│    └── terraform.tfstate # Datadogの状態を持つ
│
├── 📂 healthchecks
│    └── terraform.tfstate # Healthchecksの状態を持つ
│
└── 📂 pagerduty
      └── terraform.tfstate # PagerDutyの状態を持つ


08. 下層の分割 (推奨)

下層の分割について

下層の分割は 推奨 です。

Terraformに携わる管理者の数が少なくても採用した方がよいです。

tfstateファイルをパターンに応じて分割し、これに基づいてディレクトリ・リモートバックエンドも設計しましょう。


実行環境別 - ★★★

この分割方法について

下層分割の中でも、基本的な方法の1つです。

実行環境別にtfstateファイルを分割し、下層もこれに基づいて設計します。

この分割方法により、各実行環境の管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_environments_branch


▶ おすすめ度について

この分割方法は、様々なブログ・著名な書籍で紹介されています👀

私を含め、ほとんどの方に採用経験があるのではないでしょうか。

【実行環境別】状態の依存関係図

例えば、以下の実行環境を構築したい状況と仮定します。

  • Tes環境 (検証環境)
  • Stg環境 (ユーザー受け入れ環境)
  • Prd環境 (本番環境)

かつ、以下のプロバイダーを使用したい状況と仮定します。

  • 主要プロバイダー (AWS)
  • アプリ/インフラ監視プロバイダー (Datadog)
  • ジョブ監視プロバイダー (Healthchecks)
  • インシデント管理プロバイダー (PagerDuty)

ここで仮定した状況では、

各実行環境の tfstate ファイルは他の実行環境には依存していない

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_environments

【実行環境別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

プロバイダーアカウント別にtfstateファイルを分割することは推奨としているため、その上でディレクトリ構成を考えます。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🐱 aws-repository/
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
├── 📂 tes/ # Tes環境
│    ├── backend.tfvars # Tes環境のAWSリソースの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/ # Stg環境
└── 📂 prd/ # Prd環境
🐱 datadog-repository/
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
├── 📂 tes/
│    ├── backend.tfvars # Tes環境のDatadogの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/
└── 📂 prd/
🐱 healthchecks-repository/
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
├── 📂 tes/
│    ├── backend.tfvars # HealthchecsのTes環境の状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/
└── 📂 prd/
🐱 pagerduty-repository/
├── output.tf # 他の tfstate ファイルから依存される
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── provider.tf
├── 📂 tes/
│    ├── backend.tfvars # Tes環境のPagerDutyの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/
└── 📂 prd/

▼ 同じリポジトリの場合

プロバイダーアカウント別にtfstateファイルを分割することは推奨としているため、その上でディレクトリ構成を考えます。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🐱 repository/
├── 📂 aws/
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # Tes環境のAWSリソースの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    └── 📂 prd/ # Prd環境
│
├── 📂 datadog/
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ├── 📂 tes/
│    │    ├── backend.tfvars # Tes環境のDatadogの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/
│    └── 📂 prd/
│
├── 📂 healthchecks/
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ├── 📂 tes/
│    │    ├── backend.tfvars # Tes環境のHealthchecksの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/
│    └── 📂 prd/
│
└── 📂 pagerduty/
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── remote_state.tf # terraform_remote_state ブロックを使用する
      ├── provider.tf
      ├── 📂 tes/
      │    ├── backend.tfvars # Tes環境のPagerDutyの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/
      └── 📂 prd/

【実行環境別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

実行環境別に分割したtfstateファイルを、異なるリモートバックエンドで管理します。

tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

例えば、前述の依存関係図の状況と仮定します。

🪣 tes-aws-bucket/
│
└── terraform.tfstate # Tes環境のAWSリソースの状態を持つ
🪣 tes-datadog-bucket/
│
└── terraform.tfstate # Tes環境のDatadogの状態を持つ
🪣 tes-healthchecks-bucket/
│
└── terraform.tfstate # Tes環境のHealthchecksの状態を持つ
🪣 tes-pagerduty-bucket/
│
└── terraform.tfstate # Tes環境のPagerDutyの状態を持つ

▼ 同じリモートバックエンド x AWSアカウント別に異なる実行環境 の場合

プロバイダーアカウント別に分割したtfstateファイルを、同じリモートバックエンドで管理します。

また、AWSアカウント別に異なる実行環境を作成していると仮定します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 aws/
│    └── terraform.tfstate # Tes環境のAWSリソースの状態を持つ
│
├── 📂 datadog/
│    └── terraform.tfstate # Tes環境のDatadogの状態を持つ
│
├── 📂 healthchecks/
│    └── terraform.tfstate # Tes環境のHealthchecksの状態を持つ
│
└── 📂 pagerduty/
      └── terraform.tfstate # Tes環境のPagerDutyの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...

▼ 同じリモートバックエンド x 単一のAWSアカウント内に全ての実行環境 の場合

プロバイダーアカウント別に分割したtfstateファイルを、同じリモートバックエンドで管理します。

また、単一のAWSアカウント内に全実行環境を作成しているとします。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🪣 bucket/
├── 📂 aws/
│    ├── 📂 tes/ # Tes環境
│    │    └── terraform.tfstate # Tes環境のAWSリソースの状態を持つ
│    │
│    ├── 📂 stg/ # Stg環境
│    └── 📂 prd/ # Prd環境
│
├── 📂 datadog/
│    ├── 📂 tes/
│    │    └── terraform.tfstate # Tes環境のDatadogの状態を持つ
│    │
│    ├── 📂 stg/
│    └── 📂 prd/
│
├── 📂 healthchecks/
│    ├── 📂 tes/
│    │    └── terraform.tfstate # Tes環境のHealthchecksの状態を持つ
│    │
│    ├── 📂 stg/
│    └── 📂 prd/
│
└── 📂 pagerduty/
      ├── 📂 tes/
      │    └── terraform.tfstate # Tes環境のPagerDutyの状態を持つ
      │
      ├── 📂 stg/
      └── 📂 prd/


09. 中間層の分割 (任意)

中間層の分割について

中間層の分割は 任意 です。

Terraformに携わる管理者が多くなるほど、効力を発揮します。


運用チーム責務範囲別 - ★★

この分割方法について

運用チーム (例:アプリチーム、インフラチーム) のAWSリソースの責務範囲別でtfstateファイルを分割し、中間層もこれに基づいて設計します。

この分割方法により、各運用チームが互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_teams_branch


▶ おすすめ度について

この分割方法は、AWSドキュメント・著名な書籍で紹介されています👀

Terraformに携わるチームが複数ある非常に大規模なプロダクトほど効力を発揮します。

実際に私も現在進行形で採用しており、非常に実用的と考えています。

【チーム別】状態の依存関係図

例えば、以下の運用チームに分割した状況と仮定します。

  • frontendチーム (アプリのフロントエンド領域担当)
  • backendチーム (アプリのバックエンド領域担当)
  • sreチーム (インフラ領域担当)

ここで仮定した状況では、

各チームが管理する tfstate ファイル間で状態が相互に依存している

とします。

AWSリソース間の相互依存ではないため、循環参照は起こりません。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_teams

【チーム別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

この場合では、運用チーム責務範囲別に分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

🐱 aws-frontend-team-repository/ # frontendチーム
├── output.tf # 他の tfstate ファイルから依存される
├── provider.tf
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── cloudfront.tf
├── s3.tf
├── 📂 tes/ # Tes環境
│    ├── backend.tfvars # frontendチームの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/ # Stg環境
│    ├── backend.tfvars # frontendチームの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 prd/ # Prd環境
      ├── backend.tfvars # frontendチームの状態を持つ tfstate ファイルを指定する
      ...
🐱 aws-backend-team-repository/ # backendチーム
├── output.tf # 他の tfstate ファイルから依存される
├── provider.tf
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── elasticache.tf
├── ses.tf
├── sns.tf
├── rds.tf
├── 📂 tes
│    ├── backend.tfvars # backendチームの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg
│    ├── backend.tfvars # backendチームの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 prd
      ├── backend.tfvars # backendチームの状態を持つ tfstate ファイルを指定する
       ...
🐱 aws-sre-team-repository/ # sreチーム
├── output.tf # 他の tfstate ファイルから依存される
├── provider.tf
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── alb.tf
├── cloudwatch.tf
├── ec2.tf
├── ecs.tf
├── eks.tf
├── iam.tf
├── vpc.tf
├── 📂 tes
│    ├── backend.tfvars # sreチームの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg
│    ├── backend.tfvars # sreチームの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 prd
      ├── backend.tfvars # sreチームの状態を持つ tfstate ファイルを指定する
      ...

▼ 同じリポジトリの場合

この場合では、運用チーム責務範囲別に分割したtfstateファイルを、異なるリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

🐱 aws-repository/
├── 📂 frontend-team # frontendチーム
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── cloudfront.tf
│    ├── s3.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # frontendチームの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # frontendチームの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # frontendチームの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 backend-team # backendチーム
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── elasticache.tf
│    ├── ses.tf
│    ├── sns.tf
│    ├── rds.tf
│    ├── 📂 tes
│    │    ├── backend.tfvars # backendチームの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg
│    │    ├── backend.tfvars # backendチームの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd
│          ├── backend.tfvars # backendチームの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 sre-team # sreチーム
      ├── provider.tf
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── remote_state.tf # terraform_remote_state ブロックを使用する
      ├── alb.tf
      ├── cloudwatch.tf
      ├── ec2.tf
      ├── ecs.tf
      ├── eks.tf
      ├── iam.tf
      ├── vpc.tf
      ├── 📂 tes
      │    ├── backend.tfvars # sreチームの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg
      │    ├── backend.tfvars # sreチームの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd
           ├── backend.tfvars # sreチームの状態を持つ tfstate ファイルを指定する
           ...

【チーム別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

運用チーム責務範囲別の場合、異なるリモートバックエンドで管理するとバックエンドが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリモートバックエンドの場合

この場合では、プロバイダーアカウント別に分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 frontend-team
│    └── terraform.tfstate # frontendチームの状態を持つ
│
├── 📂 backend-team
│    └── terraform.tfstate # backendチームの状態を持つ
│
└── 📂 sre-team
      └── terraform.tfstate # sreチームの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...


プロダクトのサブコンポーネント別 - ★★

この分割方法について

プロダクトのサブコンポーネント (例:アプリ、ネットワーク、認証/認可、監視、など) 別でtfstateファイルを分割し、中間層もこれに基づいて設計します。

この分割方法により、サブコンポーネントの管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_product_sub-components_branch


▶ おすすめ度について

サブコンポーネントは、分けようと思えばいくらでも細分化できてしまいます。

細分化した数だけterraform_remote_stateブロック地獄になっていくため、適切な数 (35個くらい) にしておくように注意が必要です。

この分割方法は、後述のAWSリソースの種類グループとごっちゃになってしまう場合があるため、プロダクトのサブコンポーネントとして意識的に分割させる必要があります👍

【サブコンポーネント別】状態の依存関係図

例えば、以下のサブコンポーネントに分割した状況と仮定します。

  • application (Web3層系)
  • auth (認証/認可系)
  • monitor (監視系)
  • network (ネットワーク系)

ここで仮定した状況では、

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_product_sub-components

【サブコンポーネント別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

プロダクトのサブコンポーネント別の分割パターンの場合、異なるリポジトリで管理するとリポジトリが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリポジトリの場合

この場合では、プロダクトのサブコンポーネント別に分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

🐱 aws-repository/
├── 📂 application/
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── provider.tf
│    ├── alb.tf
│    ├── cloudfront.tf
│    ├── ec2.tf
│    ├── ecs.tf
│    ├── eks.tf
│    ├── ses.tf
│    ├── sns.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # applicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # applicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # applicationコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 auth/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── iam.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # authコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # authコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # authコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 monitor/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── cloudwatch.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # monitorコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # monitorコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # monitorコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 network
      ├── provider.tf
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── route53.tf
      ├── vpc.tf
      ├── 📂 tes/ # Tes環境
      │    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/ # Stg環境
      │    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd/ # Prd環境
           ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
           ...

【サブコンポーネント別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

プロダクトのサブコンポーネント別の分割パターンの場合、異なるリモートバックエンドで管理するとバックエンドが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリモートバックエンドの場合

この場合では、プロダクトのサブコンポーネント別に分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 application
│    └── terraform.tfstate # applicationコンポーネントの状態を持つ
│
├── 📂 auth
│    └── terraform.tfstate # authコンポーネントの状態を持つ
│
├── 📂 monitor
│    └── terraform.tfstate # monitorコンポーネントの状態を持つ
│
└── 📂 network
      └── terraform.tfstate # networkコンポーネントの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...


運用チーム責務範囲別 × プロダクトサブコンポーネント別 - ★

この分割方法について

運用チーム責務範囲別とプロダクトサブコンポーネント別を組み合わせてtfstateファイルを分割し、中間層もこれに基づいて設計します。

この分割方法により、各運用チーム内のサブコンポーネントの管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_teams_resource-type_branch


▶ おすすめ度について

この分割方法は、Terraformに携わるチームが複数あり、かつチームの人数も多い、非常に大規模なプロダクトほど効力を発揮します。

実際に私も現在進行形で採用しており、非常に実用的と考えています👍

【チーム別 × サブコンポーネント別】状態の依存関係図

以下の運用チームに分割した状況と仮定します。

また、各運用チームでTerraformを変更できる管理者が相当数するため、プロダクトのサブコンポーネント別にも分割したとします。

  • frontendチーム
    • application
    • monitor
  • backendチーム
    • application
    • monitor
  • sreチーム
    • application
    • auth
    • monitor
    • network

ここで仮定した状況では、

  • 各プロダクトのtfstateファイルの依存は一方向
  • 最終的に、sreチームの管理する tfstate ファイルに依存している

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_teams_resource-type

【チーム別 × サブコンポーネント別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

この場合では、運用チーム責務範囲別とプロダクトサブコンポーネント別を組み合わせて分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

🐱 aws-frontend-team-repository/
├── 📂 application/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── cloudfront.tf
│    ├── ses.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # frontendチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # frontendチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # frontendチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 monitor/
      ├── provider.tf
      ├── remote_state.tf # terraform_remote_state ブロックを使用する
      ├── cloudwatch.tf
      ├── 📂 tes/ # Tes環境
      │    ├── backend.tfvars # frontendチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/ # Stg環境
      │    ├── backend.tfvars # frontendチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd/ # Prd環境
            ├── backend.tfvars # frontendチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
            ...
🐱 aws-backend-team-repository/
├── 📂 application/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── api_gateway.tf
│    ├── elasticache.tf
│    ├── rds.tf
│    ├── ses.tf
│    ├── sns.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # backendチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # backendチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # backendチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 monitor/
      ├── provider.tf
      ├── remote_state.tf # terraform_remote_state ブロックを使用する
      ├── cloudwatch.tf
      ├── 📂 tes/ # Tes環境
      │    ├── backend.tfvars # backendチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/ # Stg環境
      │    ├── backend.tfvars # backendチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd/ # Prd環境
            ├── backend.tfvars # backendチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
            ...
🐱 aws-sre-team-repository/
├── 📂 application/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── alb.tf
│    ├── ec2.tf
│    ├── ecs.tf
│    ├── eks.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # sreチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # sreチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # sreチームが管理するapplicationコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 auth/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── iam.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # sreチームが管理するauthコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # sreチームが管理するauthコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # sreチームが管理するauthコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 monitor/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── cloudwatch.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # sreチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # sreチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # sreチームが管理するmonitorコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 network
      ├── provider.tf
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── route53.tf
      ├── vpc.tf
      ├── 📂 tes/ # Tes環境
      │    ├── backend.tfvars # sreチームが管理するnetworkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/ # Stg環境
      │    ├── backend.tfvars # sreチームが管理するnetworkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd/ # Prd環境
            ├── backend.tfvars # sreチームが管理するnetworkコンポーネントの状態を持つ tfstate ファイルを指定する
            ...

▼ 同じリポジトリの場合

運用チーム責務範囲別とプロダクトサブコンポーネント別を組み合わせる分割パターンの場合、同じリポジトリで管理するとリポジトリが巨大になってしまいます。

そのため、これはお勧めしません。

【チーム別 × サブコンポーネント別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

運用チーム責務範囲別とプロダクトサブコンポーネント別を組み合わせる分割パターンの場合、異なるリモートバックエンドで管理するとバックエンドが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリモートバックエンドの場合

この場合では、運用チーム責務範囲別とプロダクトサブコンポーネント別を組み合わせて分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 frontend-team
│    ├── 📂 application
│    │    └── terraform.tfstate # frontendチームが管理するapplicationコンポーネントの状態を持つ
│    │
│    └── 📂 monitor
│         └── terraform.tfstate # frontendチームが管理するmonitorコンポーネントの状態を持つ
│
├── 📂 backend-team
│    ├── 📂 application
│    │    └── terraform.tfstate # backendチームが管理するapplicationコンポーネントの状態を持つ
│    │
│    └── 📂 monitor
│          └── terraform.tfstate # backendチームが管理するmonitorコンポーネントの状態を持つ
│
└── 📂 sre-team
      ├── 📂 application
      │    └── terraform.tfstate # sreチームが管理するapplicationコンポーネントの状態を持つ
      │
      ├── 📂 auth
      │    └── terraform.tfstate # sreチームが管理するauthコンポーネントの状態を持つ
      │
      ├── 📂 monitor
      │    └── terraform.tfstate # sreチームが管理するmonitorコンポーネントの状態を持つ
      │
      └── 📂 network
            └── terraform.tfstate # sreチームが管理するnetworkコンポーネントの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...


同じテナント内のプロダクト別

この分割方法について

同じテナント (例:同じAWSアカウントの同じVPC) 内に複数の小さなプロダクトがある場合、プロダクト別でtfstateファイルを分割し、中間層もこれに基づいて設計します。

ここでいうプロダクトは、アプリを動かすプラットフォーム (例:EKS、ECS、AppRunner、EC2) とそれを取り巻くAWSリソースを指しています。

この分割方法により、各プロダクトの管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_products_branch


▶ おすすめ度について

AWSの設計プラクティスとしてプロダクトごとにVPCを分けた方がよいため、この分割方法を採用することは少ないかもしれません。

ただ現実として、各プロダクトの使用するIPアドレス数が少なく、またプロダクト別にVPCを分割するのが煩雑という現場はあります😭

【同じテナント内のプロダクト】状態の依存関係図

例えば、以下のプロダクトに分割した状況と仮定します。

ここで仮定した状況では、

  • 各プロダクトの tfstate ファイルの依存は一方向
  • 最終的に、共有networkコンポーネントの tfstate ファイルに依存している

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_products

【同じテナント内のプロダクト】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

この場合では、同じテナント内のプロダクトに分割したtfstateファイルを、異なるリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

# fooプロダクトの tfstate ファイルのリポジトリ
🐱 aws-foo-product-repository/
├── provider.tf
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── 📂 tes/ # Tes環境
│    ├── backend.tfvars # fooプロダクトの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/ # Stg環境
│    ├── backend.tfvars # fooプロダクトの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 prd/ # Prd環境
      ├── backend.tfvars # fooプロダクトの状態を持つ tfstate ファイルを指定する
      ...
# barプロダクトの tfstate ファイルのリポジトリ
🐱 aws-bar-product-repository/
├── provider.tf
├── remote_state.tf # terraform_remote_state ブロックを使用する
├── 📂 tes/ # Tes環境
│    ├── backend.tfvars # barプロダクトの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/ # Stg環境
│    ├── backend.tfvars # barプロダクトの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 prd/ # Prd環境
      ├── backend.tfvars # barプロダクトの状態を持つ tfstate ファイルを指定する
      ...
# 共有networkコンポーネントの tfstate ファイルのリポジトリ
🐱 aws-network-repository/
├── output.tf # 他の tfstate ファイルから依存される
├── provider.tf
├── route53.tf
├── vpc.tf
├── 📂 tes/ # Tes環境
│    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
│    ...
│
├── 📂 stg/ # Stg環境
│    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
│    ...
│
└── 📂 prd/ # Prd環境
      ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      ...

▼ 同じリポジトリの場合

この場合では、同じテナント内のプロダクトに分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

🐱 aws-repository/
├── 📂 foo-product/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # fooプロダクトの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # fooプロダクトの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # fooプロダクトの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 bar-product/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # barプロダクトの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # barプロダクトの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # barプロダクトの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 network
      ├── provider.tf
      ├── output.tf # 他の tfstate ファイルから依存される
      ├── route53.tf
      ├── vpc.tf
      ├── 📂 tes/ # Tes環境
      │    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/ # Stg環境
      │    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd/ # Prd環境
           ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
           ...

【同じテナント内のプロダクト】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

同じテナント内のプロダクトの場合、異なるリモートバックエンドで管理するとバックエンドが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリモートバックエンドの場合

この場合では、同じテナント内のプロダクトに分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

前述の依存関係図の状況と仮定します。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 foo-product
│    └── terraform.tfstate # fooプロダクトの状態を持つ
│
├── 📂 bar-product
│    └── terraform.tfstate # barプロダクトの状態を持つ
│
└── 📂 network
      └── terraform.tfstate # networkコンポーネントの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...


AWSリソースの種類グループ別

この分割方法について

AWSリソースの種類グループ別でtfstateファイルを分割し、中間層もこれに基づいて設計します。

この分割方法により、各AWSリソースの種類グループも管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_resource-type_branch


▶ おすすめ度について

AWSリソースの種類グループは、分けようと思えばいくらでも細分化できてしまいます。

細分化した数だけterraform_remote_stateブロック地獄になっていくため、適切な数 (35個くらい) にしておくように注意が必要です。

特にこの分割方法は、グループ数がどんどん増えていく可能性があります😇

【種類グループ別】状態の依存関係図

例えば、以下の種類グループに分割した状況と仮定します。

  • application (Webサーバー、Appサーバー系)
  • auth (認証/認可系)
  • datastore (DBサーバー系)
  • cicd (CI/CD系)
  • monitor (監視系)
  • network (ネットワーク系)

ここで仮定した状況では、

  • 各プロダクトのtfstateファイルの依存は一方向
  • 最終的に、networkグループやauthグループの tfstate ファイルに依存している

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_resource-type

【種類グループ別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

AWSリソースの種類グループ別の分割パターンの場合、異なるリポジトリで管理するとリポジトリが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリポジトリの場合

この場合では、AWSリソースの種類グループ別に分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

🐱 aws-repository/
├── 📂 application/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── alb.tf
│    ├── api_gateway.tf
│    ├── cloudfront.tf
│    ├── ec2.tf
│    ├── ecs.tf
│    ├── eks.tf
│    ├── ses.tf
│    ├── sns.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # applicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # applicationコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # applicationコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 auth/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── iam.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # authコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # authコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # authコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 cicd/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── codebuild.tf
│    ├── codecommit.tf
│    ├── codedeploy.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # cicdコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # cicdコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # cicdコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 datastore/
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── elasticache.tf
│    ├── rds.tf
│    ├── s3.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # datastoreコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # datastoreコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # datastoreコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 monitor/
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── cloudwatch.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # monitorコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # monitorコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # monitorコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 network
      ├── provider.tf
      ├── output.tf # 他の tfstate ファイルから参照できるように、outputブロックを定義する
      ├── route53.tf
      ├── vpc.tf
      ├── 📂 tes/ # Tes環境
      │    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg/ # Stg環境
      │    ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd/ # Prd環境
           ├── backend.tfvars # networkコンポーネントの状態を持つ tfstate ファイルを指定する
           ...

【種類グループ別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

AWSリソースの種類グループ別の分割パターンの場合、異なるリモートバックエンドで管理するとバックエンドが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリモートバックエンドの場合

この場合では、AWSリソースの種類グループ別に分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 application
│    └── terraform.tfstate # applicationコンポーネントの状態を持つ
│
├── 📂 auth
│    └── terraform.tfstate # authコンポーネントの状態を持つ
│
├── 📂 cicd
│    └── terraform.tfstate # cicdコンポーネントの状態を持つ
│
├── 📂 datastore
│    └── terraform.tfstate # datastoreコンポーネントの状態を持つ
│
├── 📂 monitor
│    └── terraform.tfstate # monitorコンポーネントの状態を持つ
│
└── 📂 network
      └── terraform.tfstate # networkコンポーネントの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...


AWSリソースの状態の変更頻度グループ別

この分割方法について

AWSリソースの状態の変更頻度グループ別でtfstateファイルを分割し、中間層もこれに基づいて設計します。

この分割方法により、各変更頻度グループの管理者が互いに影響を受けずに、terraformコマンドの結果を得られるようになります。

terraform_architecture_different-tfstate_update-frequence_branch


▶ おすすめ度について

変更頻度の境界が曖昧なため、この分割方法は個人的にお勧めしません。

【変更頻度グループ別】状態の依存関係図

例えば、以下の変更頻度グループに分割した状況と仮定します。

  • 変更高頻度グループ
  • 変更中頻度グループ
  • 変更低頻度グループ

ここで仮定した状況では、

  • 各プロダクトのtfstateファイルの依存は一方向
  • 最終的に、変更低頻度グループの tfstate ファイルに依存している

とします。

そのため、想定される状態の依存関係図は以下の通りになります。

なお、依存方向は状況によって異なることをご容赦ください。

terraform_architecture_different-tfstate_update-frequence

【変更頻度グループ別】リポジトリディレクトリ構成

▼ 異なるリポジトリの場合

AWSリソースの変更頻度グループ別の分割パターンの場合、異なるリポジトリで管理するとリポジトリが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリポジトリの場合

この場合では、AWSリソースの変更頻度グループ別に分割したtfstateファイルを、同じリポジトリで管理します。

例えば、tfstateファイル分割に基づいて、リポジトリディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

🐱 aws-repository/
├── 📂 high-freq # 高頻度変更グループ
│    ├── provider.tf
│    ├── remote_state.tf # terraform_remote_state ブロックを使用する
│    ├── api_gateway.tf
│    ├── cloudfront.tf
│    ├── cloudwatch.tf
│    ├── ec2.tf
│    ├── ecs.tf
│    ├── eks.tf
│    ├── iam.tf
│    ├── 📂 tes/ # Tes環境
│    │    ├── backend.tfvars # high-freqコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg/ # Stg環境
│    │    ├── backend.tfvars # high-freqコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd/ # Prd環境
│          ├── backend.tfvars # high-freqコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
├── 📂 low-freq # 低頻度変更グループ
│    ├── provider.tf
│    ├── output.tf # 他の tfstate ファイルから依存される
│    ├── route53.tf
│    ├── vpc.tf
│    ├── 📂 tes
│    │    ├── backend.tfvars # low-freqコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    ├── 📂 stg
│    │    ├── backend.tfvars # low-freqコンポーネントの状態を持つ tfstate ファイルを指定する
│    │    ...
│    │
│    └── 📂 prd
│          ├── backend.tfvars # low-freqコンポーネントの状態を持つ tfstate ファイルを指定する
│          ...
│
└── 📂 middle-freq # 中頻度変更グループ (高頻度とも低頻度とも言えないリソース)
      ├── provider.tf
      ├── remote_state.tf # terraform_remote_state ブロックを使用する
      ├── elasticache.tf
      ├── rds.tf
      ├── s3.tf
      ├── ses.tf
      ├── 📂 tes
      │    ├── backend.tfvars # middle-freqコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      ├── 📂 stg
      │    ├── backend.tfvars # middle-freqコンポーネントの状態を持つ tfstate ファイルを指定する
      │    ...
      │
      └── 📂 prd
           ├── backend.tfvars # middle-freqコンポーネントの状態を持つ tfstate ファイルを指定する
           ...

【変更頻度グループ別】リモートバックエンドのディレクトリ構成

▼ 異なるリモートバックエンドの場合

AWSリソースの変更頻度グループ別の分割パターンの場合、異なるリモートバックエンドで管理するとバックエンドが増え過ぎてしまいます。

そのため、これはお勧めしません。

▼ 同じリモートバックエンドの場合

この場合では、AWSリソースの変更頻度グループ別に分割したtfstateファイルを、異なるリモートバックエンドで管理します。

例えば、tfstateファイル分割に基づいて、リモートバックエンド内のディレクトリ構成例は以下の通りになります。

この例では、状態の依存関係図と同じ状況を仮定しています。

# Tes環境の状態のみを管理するバケット
🪣 tes-bucket/
├── 📂 high-freq
│    └── terraform.tfstate # high-freqコンポーネントの状態を持つ
│
├── 📂 middle-freq
│    └── terraform.tfstate # middle-freqコンポーネントの状態を持つ
│
└── 📂 low-freq
      └── terraform.tfstate # low-freqコンポーネントの状態を持つ
# Stg環境の状態のみを管理するバケット
🪣 stg-bucket/
│
...
# Prd環境の状態のみを管理するバケット
🪣 prd-bucket/
│
...


10. おわりに

Terraformのtfstateファイルの分割パターンをもりもり布教しました。

ぜひ採用してみたい分割パターンはあったでしょうか。

Terraformの開発現場の具体的な要件は千差万別であり、特にtfstateファイル間の状態の依存関係は様々です。

もし、この記事を参考に設計してくださる方は、分割パターンを現場に落とし込んで解釈いただけると幸いです🙇🏻‍


「自分を信じても…信頼に足る仲間を信じても…誰にもわからない…」

(お友達の@nwiizo, 2023, Terraform Modules で再利用できるので最高ではないでしょうか?)


謝辞

今回、Terraformの分割パターンの収集にあたり、以下の方々からの意見・実装方法も参考にさせていただきました。

(アルファベット順)

この場で感謝申し上げます🙇🏻‍


記事関連のおすすめ書籍