Snowflake × Terraform のディレクトリ構成パターンを比較検討してみた

Snowflake × Terraform のディレクトリ構成パターンを比較検討してみた

2025.09.07

はじめに

データ事業本部のkasamaです。今回はTerraformで開発/本番環境のSnowflakeを管理する際のディレクトリ構成について自分の中で考慮したポイントをまとめたいと思います。

前提

前提として、オープンソース版のTerraformの話であり、HCP Terraform(クラウド版)は考慮していません。
以下ブログの構成を参考させていただき、少し自分なりにカスタマイズして使わせていただきます。
https://dev.classmethod.jp/articles/snowflake-terraform-design-with-functional-and-access-role/
https://dev.classmethod.jp/articles/snowflake-how-to-terraform-with-github-actions/

以下のディレクトリ構成を元に検討していきたいと思います。moduleをaccess role + リソース単位で作成し、dev/prdごとのmain.tfで呼び出す実装です。terraformのinitやplan,applyコマンドの実行はGithub Actions経由で行います。

snowflake-terraform-sample % tree
.
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn
│   └── create_state_gha_resources.yml
├── environments
│   ├── dev
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   └── prd
│       ├── backend.tf
│       ├── main.tf
│       ├── outputs.tf
│       ├── variables.tf
│       └── versions.tf
├── modules
│   ├── access_role_and_database
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── access_role_and_file_format
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── access_role_and_schema
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── access_role_and_stage
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── access_role_and_storage_integration
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── access_role_and_warehouse
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── aws_storage_integration
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── functional_role
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
└── README.md

dev/prdでディレクトリを分けるか

dev/prdなどの複数環境ある場合において、ディレクトリ構成を分けないで実装する方法もあります。
実際に動作確認はしていないので、こう実装できるだろうという想定の元記載しますが、環境ごとにbackend.tfファイルやtfvarsファイルを作成し、CI/CDの設定でterraformコマンド実行時に引数を指定するなどの工夫をすることで、main.tfの重複なくDRY原則に沿った形の実装も可能だと思います。

snowflake-terraform/
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn
│   └── create_state_gha_resources.yml
├── terraform/
│   ├── main.tf
│   ├── variables.tf
│   ├── outputs.tf
│   ├── versions.tf
│   ├── backends/               # 環境別backend設定
│   │   ├── dev-backend.tf
│   │   └── prd-backend.tf
│   ├── environments/           # 環境別変数値
│   │   ├── dev.tfvars
│   │   └── prd.tfvars
├── modules
│   ├── :

比較

それぞれを比較してみました。

比較項目 環境別ディレクトリ構成 変数分離構成(DRY原則)
CI/CD設定 ⭕️ディレクトリを環境ごとに指定
シンプルな設定
⚠️terraform init コマンド実行時に-backend-configを指定したり、terraform plan, applyコマンド時に-var-fileの指定が必要
環境差異 ⭕️ ディレクトリごとにmain.tfを作成しmoduleを呼び出す ⭕️環境別tfvarsファイルで差異を吸収
メンテナンス性 ⚠️ 低い
変更を全環境に反映が必要
⭕️ 高い
1箇所の変更で完了する
誤操作リスク ⭕️ 非常に低い
物理的に分離
⚠️ 低い
CI/CD実行で制御
推奨ケース 環境差異が大きい場合
一般的に推奨される構成
環境差異が小さい場合
DRY原則を重視する場合

HashicorpやGoogle Cloudのベストプラクティスでは、環境別ディレクトリ構成が推奨されていますが、プロジェクトの状況に応じて適切な構成を選択することが重要です。特に、環境差異が大きい場合や運用シンプルさを重視する場合には、環境別ディレクトリ構成が有効です。Snowflakeにおいてもdev/prdごとにwarehouseサイズを分けたり、Network policyの設定が異なったりするケースもあると思いますので、環境差異の設定がシンプルで良いかと思います。運用していく中で、環境差異が小さく、実装重複のデメリットが大きいと感じたタイミングで変数分離構成を検討すれば良いと思います。

以下の記事を参考にしました。
https://developer.hashicorp.com/terraform/language/style#module-structure
https://cloud.google.com/docs/terraform/best-practices/root-modules?hl=ja
https://zenn.dev/sway/articles/terraform_style_envcomparisontable
https://medium.com/snowflake/so-you-want-to-terraform-snowflake-a6d16ca3237e

module構成はリソースタイプごと vs ユーザータイプごと

現在の構成ですとmoduleをリソースタイプごと(database,file_format,schemaなど)に分けていますが、以下のようにユーザータイプごとにリソースをまとめる実装も選択肢としてはあると思います。

snowflake-terraform/
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn/
│   └── create_state_gha_resources.yml
├── environments/
│   ├── dev/
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   └── prd/
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
├── modules/
│   ├── admin/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── versions.tf
│   ├── analyst/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── versions.tf
│   ├── data_engineer/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── versions.tf
│   ├── aws_storage_integration/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── versions.tf
│   └── network_policy/
│       ├── main.tf
│       ├── variables.tf
│       └── versions.tf

ユーザータイプごとのmain.tfで使用するresourceを定義し、environments/<環境>/main.tfで呼び出す実装です。

modules/admin/main.tf
resource "snowflake_database" "main" {
 :
}
resource "snowflake_schema" "main" {
 :
}
resource "snowflake_warehouse" "main" {
 :
}
environments/<環境>/main.tf
module "sample_admin" {
  source = "../../modules/admin"
	:
}	

比較

それぞれを比較してみました。

比較項目 リソースタイプごと ユーザータイプごと
コードの重複 ⭕️ 各リソースの実装は一箇所
DRY原則に準拠
⚠️ 同じリソース定義が複数モジュールに散在
(例:warehouseが各役割で重複)
新規リソース追加時 ⚠️ 複数モジュールの呼び出しが必要
(database + schema + warehouse等)
⭕️ 1つのモジュール呼び出しで完結
役割に必要なリソースが一括作成
既存リソース改修時 ⭕️ 1箇所の変更で全体に反映
(例:warehouse設定を一括変更)
⚠️ 同じ変更を複数モジュールに反映必要
(例:各役割のwarehouse設定を個別修正)
依存関係の管理 ⚠️ モジュール間でoutputs/inputsの配線が増える
(例:database.idをschemaモジュールに渡す)
⭕️ 役割内で自己完結しやすい
学習コスト ⚠️ モジュール間の配線理解が必要 ⭕️ 「人の役割」で直感的に把握しやすい
推奨ケース リソースの再利用性を重視する場合
一般的に推奨される構成
役割ごとのリソースパターンが固定的な場合
新規追加の簡便性を重視する場合

一般的には、リソースタイプごとに管理する方がDRY原則に沿っており、コードの重複を減らすことができます。ただし、プロジェクトの状況や役割ごとのリソースパターンが固定的である場合、ユーザータイプごとに管理することも選択肢の一つとして考慮すべきです。ユーザータイプごとは、役割ごとに作成するリソースパターンが固定的であり、admin_1,admin_2...admin_50のように大量の同一ユーザータイプの新規追加を簡単に行いたい場合は選択しても良いかと考えています。

なお、両方の利点を活かす構成として、ユーザータイプごとのmoduleをenvironments/<環境>/main.tfから呼び出し、ユーザータイプごとのmodule内で、リソースタイプごとのmoduleを呼び出す方法があります。

snowflake-terraform-sample/
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn/
│   └── create_state_gha_resources.yml
├── environments/
│   ├── dev/
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   └── prd/
│       ├── backend.tf
│       ├── main.tf
│       ├── outputs.tf
│       ├── variables.tf
│       └── versions.tf
├── modules/
│   ├── base_resources/  # 基本リソースモジュール(DRY原則)
│   │   ├── access_role_and_database/
│   │   ├── access_role_and_file_format/
│   │   ├── access_role_and_schema/
│   │   ├── functional_role/
│   │   └── ... (他のリソース)
│   └── user_types/  # ユーザータイプごとのモジュール
│       ├── admin/
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       ├── data_engineer/
│       └── analyst/
└── README.md
environments/dev/main.tf
# Admin用リソース一式
module "project_a_admin" {
  source = "../../modules/user_types/admin"

  project_name                = "PROJECT_A"
  environment                 = "DEV"
  warehouse_size              = "XSMALL"
  data_retention_time_in_days = 1

  providers = {
    snowflake.sysadmin      = snowflake.sysadmin
    snowflake.securityadmin = snowflake.securityadmin
  }
}

# 複数のAdminユーザーが必要な場合は簡単に追加可能
module "project_b_admin" {
  source = "../../modules/user_types/admin"

  project_name                = "PROJECT_B"
  environment                 = "DEV"
  warehouse_size              = "XSMALL"
  data_retention_time_in_days = 1

  providers = {
    snowflake.sysadmin      = snowflake.sysadmin
    snowflake.securityadmin = snowflake.securityadmin
  }
}
modules/user_types/admin/main.tf
locals {
  prefix = upper("${var.project_name}_${var.environment}_ADMIN")
}

# Functional Role作成
module "functional_role" {
  source = "../../base_resources/functional_role"

  role_name = "${local.prefix}_ROLE"
  comment   = "Admin functional role for ${var.project_name}"
}

# Database作成
module "database" {
  source = "../../base_resources/access_role_and_database"

  database_name                = "${local.prefix}_DB"
  comment                     = "Admin database for ${var.project_name}"
  data_retention_time_in_days = var.data_retention_time_in_days

  access_role_name    = "${local.prefix}_DB_ACCESS_ROLE"
  access_role_comment = "Access role for admin database"

  usage_grants         = [module.functional_role.role_name]
  create_schema_grants = [module.functional_role.role_name]
  monitor_grants       = [module.functional_role.role_name]
}

# Schema作成
module "schema_public" {
  source = "../../base_resources/access_role_and_schema"

  database_name = module.database.database_name
  schema_name   = "PUBLIC"
  comment       = "Public schema for admin"

  access_role_name    = "${local.prefix}_PUBLIC_ACCESS_ROLE"
  access_role_comment = "Access role for public schema"

  usage_grants        = [module.functional_role.role_name]
  create_table_grants = [module.functional_role.role_name]
}

# File Format作成
module "file_format_csv" {
  source = "../../base_resources/access_role_and_file_format"

  database_name     = module.database.database_name
  schema_name       = module.schema_public.schema_name
  file_format_name  = "${local.prefix}_CSV_FORMAT"
  format_type       = "CSV"
  comment          = "CSV file format for admin"

  access_role_name    = "${local.prefix}_CSV_FORMAT_ACCESS_ROLE"
  access_role_comment = "Access role for CSV file format"

  usage_grants = [module.functional_role.role_name]
}

module構成は少し複雑になりますが、「admin_1, admin_2...admin_50のように大量の同一ユーザータイプの新規追加を簡単に行いたい」というユーザータイプごとの利点と、「リソースの変更が必要な場合、一箇所の修正で全体に反映」というリソースタイプごとの利点の両方を実現できます。

リソース数が増加した際のディレクトリ構成

これまでの実装ですと、environments/<環境>/main.tfの1ファイルからmoduleを呼び出す実装でした。リソース数が少ない時はこの構成でも良いのですが、100,200と増加した時に1ファイルで管理していくのはかなり大変になると思います。解決策としていくつか方法はあると思いますのでまとめたいと思います。

リソースごとにファイル分離構成

snowflake-terraform-sample % tree
.
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn
│   └── create_state_gha_resources.yml
├── environments
│   ├── dev
│   │   ├── backend.tf
│   │   ├── main.tf → 共通処理
│   │   ├── databases.tf → リソース別
│   │   ├── file_formats.tf → リソース別
│   │   ├── schemas.tf → リソース別
│   │   ├── ... (他のリソース)
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   └── prd
│       ├── backend.tf
│       ├── main.tf → 共通処理
│       ├── databases.tf → リソース別
│       ├── file_formats.tf → リソース別
│       ├── schemas.tf → リソース別
│       ├── ... (他のリソース)
│       ├── outputs.tf
│       ├── variables.tf
│       └── versions.tf
├── modules/
│   ├── access_role_and_database/
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── :

databases.tf,file_formats.tfなどのリソースごとにtfファイルを作成し管理していくパターンです。databasesの中でもコード量が増加した場合は、databases_a.tf,databases_b.tfのようにファイル分割する方法もあります。ただファイル分割しすぎると環境フォルダ直下にファイル数が多くなり、それはそれで管理しにくくなるデメリットも発生すると思います。

YAMLファイルを活用したサブディレクトリ構成

snowflake-terraform-sample/
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn/
│   └── create_state_gha_resources.yml
├── environments/
│   ├── dev/
│   │   ├── backend.tf
│   │   ├── main.tf              # YAMLを読み込んでmodule呼び出し
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   ├── versions.tf
│   │   └── yml/           # YAML定義
│   │       ├── databases/
│   │       │   ├── database_1.yml
│   │       │   ├── database_2.yml
│   │       ├── file_formats/
│   │       │   ├── file_format_1.yml
│   │       │   ├── file_format_2.yml
│   │       ├── schemas/
│   │       │   ├── schema_1.yml
│   │       │   ├── schema_2.yml
│   │       └── ... (他のリソース)
│   └── prd/
│       ├── backend.tf
│       ├── main.tf              # YAMLを読み込んでmodule呼び出し
│       ├── outputs.tf
│       ├── variables.tf
│       ├── versions.tf
│       └── yml/           # リソース定義
│           ├── databases/
│           │   ├── database_1.yml
│           │   ├── database_2.yml
│           ├── file_formats/
│           │   ├── file_format_1.yml
│           │   ├── file_format_2.yml
│           ├── schemas/
│           │   ├── schema_1.yml
│           │   ├── schema_2.yml
│           └── ... (他のリソース)
├── modules/
│   ├── access_role_and_database/
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── :

YAMLファイルでパラメータを定義して、environments/<環境>/main.tfで参照する実装です。

environments/dev/yml/databases/database_1.yml
name: DATABASE_1_DEV
comment: "Development database 1"
data_retention_time_in_days: 1

access_role:
  name: DATABASE_1_DEV_ACCESS_ROLE
  comment: "Access role for database 1"

grants:
  usage:
    - ADMIN_ROLE_1
    - SYSADMIN
  create_schema:
    - ADMIN_ROLE_1
  monitor:
    - ADMIN_ROLE_1
environments/dev/main.tf
# ============================================================
# YAMLファイルの読み込み
# ============================================================

locals {
  # 各YAMLファイルをデコード
  database_configs = {
    for f in fileset("${path.module}/yml/databases", "*.yml") :
    trimsuffix(f, ".yml") => yamldecode(file("${path.module}/yml/databases/${f}"))
  }

  file_format_configs = {
    for f in fileset("${path.module}/yml/file_formats", "*.yml") :
    trimsuffix(f, ".yml") => yamldecode(file("${path.module}/yml/file_formats/${f}"))
  }

  schema_configs = {
    for f in fileset("${path.module}/yml/schemas", "*.yml") :
    trimsuffix(f, ".yml") => yamldecode(file("${path.module}/yml/schemas/${f}"))
  }
}

# ============================================================
# Database モジュール呼び出し
# ============================================================

module "database_1" {
  source = "../../modules/access_role_and_database"

  database_name               = local.database_configs["database_1"].name
  comment                    = local.database_configs["database_1"].comment
  data_retention_time_in_days = local.database_configs["database_1"].data_retention_time_in_days

  access_role_name    = local.database_configs["database_1"].access_role.name
  access_role_comment = local.database_configs["database_1"].access_role.comment

  usage_grants         = local.database_configs["database_1"].grants.usage
  create_schema_grants = local.database_configs["database_1"].grants.create_schema
  monitor_grants       = local.database_configs["database_1"].grants.monitor

  providers = {
    snowflake.sysadmin      = snowflake.sysadmin
    snowflake.securityadmin = snowflake.securityadmin
  }
}

module "database_2" {
  source = "../../modules/access_role_and_database"

  database_name               = local.database_configs["database_2"].name
  comment                    = local.database_configs["database_2"].comment
  data_retention_time_in_days = local.database_configs["database_2"].data_retention_time_in_days

  access_role_name    = local.database_configs["database_2"].access_role.name
  access_role_comment = local.database_configs["database_2"].access_role.comment

  usage_grants         = local.database_configs["database_2"].grants.usage
  create_schema_grants = local.database_configs["database_2"].grants.create_schema
  monitor_grants       = try(local.database_configs["database_2"].grants.monitor, [])

  providers = {
    snowflake.sysadmin      = snowflake.sysadmin
    snowflake.securityadmin = snowflake.securityadmin
  }
}

YAMLを使用することで、main.tfのコード量を減らしつつ、サブディレクトリ構成を取ることができます。デメリットとしては、YAMLの構文エラーやデータ型の不一致がterraform plan実行時まで発見できず、terraform validateもYAML内の値を検証できません。また、YAMLでは依存関係が文字列で記述されるため、HCLのような明示的な参照(module.database_1.name)と異なり、どのリソースに依存しているか把握しにくくなります。これらの要因により、デバッグや保守が複雑化する可能性があります。

以下の記事はYAMLを活用した構成で参考にさせていただきました。
https://datumstudio.jp/blog/0131_terraform_snowflake_role_creating/

State分離構成

snowflake-terraform-sample/
├── .github/
│   └── workflows/
│       ├── dev-snowflake-terraform-cicd.yml
│       └── prd-snowflake-terraform-cicd.yml
├── cfn/
│   └── create_state_gha_resources.yml
├── environments/
│   ├── dev/
│       ├── common/
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       ├── databases/
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       ├── file_formats/
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       └── schemas/
│           ├── backend.tf
│           ├── main.tf
│           ├── outputs.tf
│           ├── variables.tf
│           └── versions.tf
│   └── prd/
│       ├── common/
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       ├── databases/
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       ├── file_formats/
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── variables.tf
│       │   └── versions.tf
│       └── schemas/
│           ├── backend.tf
│           ├── main.tf
│           ├── outputs.tf
│           └── variables.tf
├── modules/
│   ├── access_role_and_database/
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── variables.tf
│   │   └── versions.tf
│   ├── :

State分離した場合は、database、schemaのように依存関係があるリソースはterraform_remote_stateによる参照が必要です。

environments/dev/databases/outputs.tf
output "database_1_name" {
  value = module.database_1.database_name
}
environments/dev/schemas/main.tf
# 他のStateファイルを読み込む
data "terraform_remote_state" "databases" {
  backend = "s3"
  config = {
    bucket = "terraform-state-bucket"
    key    = "snowflake/dev/databases/terraform.tfstate"  # ← 別のStateファイル
    region = "ap-northeast-1"
  }
}

module "schema_1" {
  source = "../../modules/access_role_and_schema"
  # remote_state経由で値を取得
  database_name = data.terraform_remote_state.databases.outputs.database_1_name
  schema_name = "PUBLIC"
}

State分離の場合は、tfファイルのみでサブディレクトリ構成管理ができますが、リソースごとのState管理となるので、依存関係の管理が複雑になります。また、デプロイ順序を考慮する必要があり(common → databases → schemas)、CI/CDパイプラインの設定も複雑化します。

比較

それぞれを比較してみました。

比較項目 ファイル分離構成 YAML活用構成 State分離構成
ディレクトリ構造 ⭕️ フラット
環境直下に.tfファイル配置
⭕️ 階層的
YAMLをサブディレクトリで整理
⭕️ 階層的
リソース種別ごとにディレクトリ
1ファイルのコード量 ⚠️ 多い
各リソースを1tfで定義
⭕️ 少ない
YAMLで定義、main.tfは簡潔
⭕️ 少ない
outputとdata参照が追加
State管理 ⭕️ 単一State ⭕️ 単一State ⚠️ 複数State(分離)
依存関係管理 ⭕️ 簡単
同一State内でmodule.xxx参照
⚠️ 暗黙的
YAML内の文字列参照
⚠️ 複雑
terraform_remote_state必須
CI/CD設定 ⭕️ シンプル
1回の実行で完了
⭕️ シンプル
1回の実行で完了
⚠️ 複雑
実行順序の制御が必要
パフォーマンス ⭕️ 標準 ⭕️ 標準 ⭕️ 高
変更箇所のみ実行可能
学習コスト ⭕️ 低い
標準的なTerraform構成
⚠️ 中程度
独自YAML構造の理解必要
⚠️ 高い
State間参照の理解必須
推奨ケース 単一State管理かつリソース数が少ない場合 単一State管理かつサブディレクトリ構成を取りたい場合 サブディレクトリ構成をtfファイルのみで取りたい場合

個人的な見解としては、まずは単一Stateでファイル分離構成から始めるのが良いと考えています。この構成は最もシンプルで、Terraformの標準的な使い方に沿っているため、チームメンバーの学習コストも低く抑えられます。初期段階ではdatabases.tf、schemas.tfといったリソースタイプごとのファイル分割で十分管理可能だと思います。
リソース数が増加してきた段階で、State分離構成への移行を検討するのが現実的だと思います。State分離は依存関係の管理が複雑になるものの、大規模環境ではパフォーマンス向上や、影響範囲の限定化といったメリットがあると考えられます。
YAML活用構成については、デバッグの複雑化によるデメリットが大きいと判断しています。
結論として、「シンプルに始めて、必要に応じて段階的に複雑化する」というアプローチが、良いのではないかと現段階では考えています。

Terragruntという選択肢もあります。これは複数State管理に特化したツールで、大規模なリソース管理(例:100個以上)が最初から想定される場合や、チームに学習リソースがある場合には有効な選択肢となります。
https://zenn.dev/simpleform_blog/articles/20240701-multi-account-snowflake-with-terragrunt

最後に

上記で記載した内容はあくまで執筆段階の私の考えであり、実際に何年も運用したら変わる可能性があると思いますので、参考までにしていただければと思います。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.