このドキュメントでは、ルート モジュールを使用する際に考慮すべきガイドラインと推奨事項について説明します。
ルート構成(ルート モジュール)は、Terraform CLI を実行する作業ディレクトリです。ルート構成が次の標準(該当する場合は以前の Terraform ガイドライン)に準拠していることを確認します。一般的なガイドラインよりもルート モジュールの明示的な推奨事項が優先されます。
このガイドでは Terraform の概要は説明しません。 Google Cloudで Terraform を使用する方法については、Terraform を使ってみるをご覧ください。
各ルート モジュールのリソース数を最小限に抑える
同じディレクトリと状態に含まれるリソースが多くなり、1 つのルート構成が大きくならないようにすることが重要です。特定のルート構成に含まれるすべてのリソースは、Terraform が実行されるたびに更新されます。1 つの状態に含まれるリソースが多すぎる場合、実行が遅くなる可能性があります。原則として、1 つの状態に含まれるリソースは 100 個未満に制限します(理想的には数十個程度)。
アプリケーションごとに個別のディレクトリを使用する
アプリケーションとプロジェクトを個別に管理するには、各アプリケーションとプロジェクトのリソースをそれぞれの Terraform ディレクトリに配置します。サービスは、特定のアプリケーションや、共有ネットワークなどの共通サービスを表します。特定のサービスのすべての Terraform コードを 1 つのディレクトリ(サブディレクトリを含む)にネストします。
環境固有のサブディレクトリにアプリケーションを分割する
 Google Cloudにサービスをデプロイする場合、サービスの Terraform 構成を 2 つの最上位ディレクトリに分割します。1 つがサービスの実際の構成が格納されている modules ディレクトリ、もう 1 つが各環境のルート構成が含まれる environments ディレクトリです。
-- SERVICE-DIRECTORY/
   -- OWNERS
   -- modules/
      -- <service-name>/
         -- main.tf
         -- variables.tf
         -- outputs.tf
         -- provider.tf
         -- README
      -- ...other…
   -- environments/
      -- dev/
         -- backend.tf
         -- main.tf
      -- qa/
         -- backend.tf
         -- main.tf
      -- prod/
         -- backend.tf
         -- main.tf
環境ディレクトリを使用する
環境間でコードを共有するには、参照モジュールを使用します。通常、これはサービス用の共有 Terraform の基本構成を含むサービス モジュールになります。サービス モジュールでは、共通入力をハードコードし、環境固有の入力のみを変数にする必要があります。
各環境ディレクトリには、次のファイルが含まれている必要があります。
backend.tfファイル。Terraform のバックエンド状態の場所(通常は Cloud Storage)を宣言します。- サービス モジュールをインスタンス化する 
main.tfファイル 
各環境ディレクトリ(dev、qa、prod)は、デフォルトの Terraform ワークスペースに対応し、そのサービスのバージョンを環境にデプロイします。これらのワークスペースでは、環境固有のリソースが独自のコンテキストに分離されます。デフォルトのワークスペースのみを使用します。
次の理由により、環境内で複数の CLI ワークスペースを使用することはおすすめしません。
- 各ワークスペースの構成を検査するのが難しい場合があります。
 - 環境を分離する際に共有バックエンドを使用すると単一障害点になるため、複数のワークスペースに単一の共有バックエンドを使用することはおすすめしません。
 - コードを再利用することはできますが、現在のワークスペース変数(
terraform.workspace == "foo" ? this : thatなど)に基づいて切り替える必要があるため、コードが読みにくくなります。 
詳しくは以下をご覧ください。
リモート状態から出力を公開する
ルート モジュールからモジュール インスタンスの有用な出力を公開していることを確認してください。
たとえば、次のコード スニペットは、プロジェクト ファクトリ モジュール インスタンスからのプロジェクト ID 出力をルート モジュールの出力として渡します。
# Project root module
terraform {
  backend "gcs" {
    bucket  = "BUCKET"
  }
}
module "project" {
  source  = "terraform-google-modules/project-factory/google"
  ...
}
output "project_id" {
  value       = module.project.project_id
  description = "The ID of the created project"
}
他の Terraform 環境とアプリケーションは、ルート モジュール レベルの出力のみを参照できます。
リモート状態を使用すると、ルート モジュールの出力を参照できます。他の依存アプリによる構成を許可するには、サービスのエンドポイントに関連する情報をリモート状態にエクスポートします。
# Networks root module
data "terraform_remote_state" "network_project" {
  backend = "gcs"
  config = {
    bucket = "BUCKET"
  }
}
module "vpc" {
  source  = "terraform-google-modules/network/google"
  version = "~> 9.0"
  project_id   = data.terraform_remote_state.network_project.outputs.project_id
  network_name = "vpc-1"
  ...
}
環境ディレクトリから共有サービス モジュールを呼び出すときなど、次のように子モジュール全体を再度エクスポートするほうが良い場合があります。
output "service" {
  value       = module.service
  description = "The service module outputs"
}
マイナー プロバイダのバージョンに固定する
ルート モジュールで、各プロバイダを宣言し、マイナー バージョンに固定します。これにより、固定されたターゲットを維持しながら、新しいパッチリリースに自動アップグレードできます。整合性を保つために、バージョン ファイルに versions.tf という名前を付けます。
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0.0"
    }
  }
}
変数を tfvars ファイルに格納する
ルート モジュールの場合は、.tfvars 変数ファイルを使用して変数を指定します。整合性を保つために、変数ファイルに terraform.tfvars という名前を付けます。
別の var-files または var='key=val' コマンドライン オプションを使用して変数を指定しないでください。コマンドライン オプションはエフェメラルなものであり、簡単に削除できます。デフォルトの変数ファイルを使用すると、予測しやすくなります。
.terraform.lock.hcl ファイルをチェックインする
ルート モジュールの場合、.terraform.lock.hcl 依存関係ロックファイルをソース管理にチェックインする必要があります。これにより、任意の構成に対するプロバイダ選択の変更を追跡および確認できます。