一般的なスタイルと構造に関するベスト プラクティス

このドキュメントでは、Terraform 構成の基本的なスタイルと構造に関する推奨事項について説明します。これらの推奨事項は、再利用可能な Terraform モジュールとルート構成に適用されます。

このガイドでは Terraform の概要は説明しません。Google Cloud で Terraform を使用する方法については、Terraform を使ってみるをご覧ください。

標準のモジュール構造に従う

  • Terraform モジュールは、標準のモジュール構造に従う必要があります。
  • デフォルトでリソースが配置されている main.tf ファイルを使用してモジュールを起動します。
  • すべてのモジュールに、Markdown 形式の README.md ファイルを含めます。README.md ファイルに、モジュールに関する基本のドキュメントを含めます。
  • 例ごとに個別のサブディレクトリを使用して、例を examples/ フォルダに配置します。各例について、詳細な README.md ファイルを含めます。
  • 独自のファイルと network.tfinstances.tfloadbalancer.tf などの記述名を使用して、リソースの論理グループを作成します。
    • すべてのリソースに独自のファイルを割り当てることは避けます。共有目的別にリソースをグループ化します。たとえば、dns.tfgoogle_dns_managed_zonegoogle_dns_record_set を組み合わせます。
  • モジュールのルート ディレクトリには、Terraform(*.tf)とリポジトリ メタデータ ファイル(README.mdCHANGELOG.md など)のみを含めます。
  • 追加のドキュメントは docs/ サブディレクトリに配置します。

命名規則を採用する

  • すべての構成オブジェクトに名前を付けます。単語の区切りにはアンダースコアを使用します。これにより、リソースタイプ、データソース タイプ、その他の事前定義された値の命名規則と一貫性を保つことができます。この規則は、名前の引数には適用されません。

    推奨:

    resource "google_compute_instance" "web_server" {
      name = "web-server"
    }
    

    非推奨:

    resource "google_compute_instance" "web-server" {
      name = "web-server"
    }
    
  • リソースタイプの 1 つ(モジュール全体の単一のロードバランサなど)に対する参照を簡素化するため、リソースに main という名前を付けます。

    • some_google_resource.my_special_resource.idsome_google_resource.main.id の違いを思い出すには、追加のメンタルワークが必要です。
  • 同じタイプのリソースを区別するには(たとえば、primarysecondary)、意味のあるリソース名を指定します。

  • リソース名を単数形にします。

  • リソース名でリソースタイプを繰り返さないでください。次に例を示します。

    推奨:

    resource "google_compute_global_address" "main" { ... }
    

    非推奨:

    resource "google_compute_global_address" "main_global_address" { … }
    

変数を慎重に使用する

  • すべての変数を variables.tf で宣言します。
  • 変数には、用途や目的がすぐわかる名前を付けます。
    • 入力、ローカル変数、ディスクサイズや RAM サイズなどの数値を表す出力には、単位(ram_size_gb など)を使用する必要があります。Google Cloud APIs には標準単位がないため、変数名に単位を付けると、構成のメンテナンス担当者にとって想定される入力単位が明確になります。
    • ストレージの単位にはバイナリ単位の接頭辞(1,024 の累乗)(kibimebigibi)を使用します。他のすべての測定単位には 10 進単位の接頭辞(1,000 の累乗)(kilomegagiga)を使用します。この使用法は、Google Cloud 内の使用法と同じです。
    • 条件付きロジックを簡素化するには、ブール値変数に正の名前(enable_external_access など)を付けます。
  • 変数には説明を含める必要があります。公開モジュールの自動生成ドキュメントには、説明が自動的に含まれます。説明により、説明的な名前で提供できない追加のコンテキストを新しいデベロッパーに提供できます。
  • 変数の定義型を指定します。
  • 必要に応じて、デフォルト値を指定します。
    • 環境に依存しない値(ディスクサイズなど)を持つ変数の場合は、デフォルト値を指定します。
    • 環境に固有の値(project_id など)を持つ変数の場合、デフォルト値は指定しないでください。このように、呼び出しモジュールでは意味のある値を提供する必要があります。
  • 変数(空の文字列やリストなど)に空のデフォルトを使用するのは、変数を空のままにすることが有効な設定で、ベースとなる API に拒否されない場合に限られます。
  • 変数の使用は慎重に行ってください。インスタンスまたは環境ごとに異なる値のみをパラメータ化します。変数を公開するかどうかを決定するときは、変数を変更するための具体的なユースケースがあることを確認してください。変数が必要になる可能性がわずかしない場合は、その変数を公開しないでください。
    • デフォルト値を含む変数の追加には下位互換性があります。
    • 変数の削除には下位互換性がありません。
    • リテラルが複数の場所で再利用されている場合は、ローカル値を変数として公開せずに使用できます。

出力を公開する

  • すべての出力を outputs.tf ファイルに整理します。
  • すべての出力にわかりやすい説明を入力します。
  • 出力の説明を README.md ファイルに記述します。terraform-docs などのツールを使用して、commit の説明を自動生成します。
  • ルート モジュールが参照または共有する必要があるすべての有用な値を出力します。特にオープンソースまたは使用頻度の高いモジュールの場合は、消費される可能性があるすべての出力を公開します。
  • 入力変数を介して出力を直接渡さないでください。渡してしまうと、依存関係グラフに適切に追加できなくなります。暗黙的な依存関係を確実に作成するには、リソースから参照属性が出力されるようにします。インスタンスの入力変数を直接参照するのではなく、次のように属性を渡します。

    推奨:

    output "name" {
      description = "Name of instance"
      value       = google_compute_instance.main.name
    }
    

    非推奨:

    output "name" {
      description = "Name of instance"
      value       = var.name
    }
    

データソースを使用する

  • 参照するリソースの横にデータソースを配置します。たとえば、インスタンスの起動に使用するイメージを取得する場合は、データソースを独自のファイルに収集するのではなく、インスタンスと一緒に配置します。
  • データソース数が多い場合は、専用の data.tf ファイルに移動することを検討してください。
  • 現在の環境に関連するデータを取得するには、変数またはリソースの補間を使用します。

カスタム スクリプトの使用を制限する

  • スクリプトは必要な場合にのみ使用してください。スクリプトによって作成されたリソースの状態が、Terraform で考慮または管理されることはありません。
    • 可能であれば、カスタム スクリプトは使用しないでください。Terraform リソースが目的の動作をサポートしていない場合にのみ使用してください。
    • 使用するすべてのカスタム スクリプトは、作成の理由について(可能であれば廃止するタイミングも)明確に文書化しておく必要があります。
  • Terraform は、プロビジョナ(local-exec プロビジョナを含む)を介してカスタム スクリプトを呼び出すことができます。
  • Terraform で呼び出したカスタム スクリプトを scripts/ ディレクトリに配置します。

ヘルパー スクリプトを別のディレクトリに含める

  • Terraform による呼び出しの対象外であるヘルパー スクリプトを helpers/ ディレクトリに編成します。
  • 説明と呼び出しの例を含めて、README.md ファイル内にヘルパー スクリプトを文書化します。
  • ヘルパー スクリプトが引数を受け入れる場合は、引数チェックと --help 出力を提供します。

静的ファイルを別のディレクトリに配置する

  • Terraform が参照するだけで、実行はしない静的ファイル(Compute Engine インスタンスに読み込まれた起動スクリプトなど)は、files/ ディレクトリに配置する必要があります。
  • 長い HereDocs は、HCL とは別の外部ファイルに配置します。これらは file() 関数で参照してください。
  • Terraform の templatefile 関数を使用して読み取ったファイルには、ファイル拡張子 .tftpl を使用します。
    • テンプレートは、templates/ ディレクトリに配置する必要があります。

ステートフル リソースを保護する

データベースなどのステートフル リソースの場合は、削除保護が有効になっていることを確認します。次に例を示します。

resource "google_sql_database_instance" "main" {
  name = "primary-instance"
  settings {
    tier = "D0"
  }

  lifecycle {
    prevent_destroy = true
  }
}

組み込みの書式設定を使用する

すべての Terraform ファイルは、terraform fmt の標準に準拠している必要があります。

式の複雑さを制限する

  • 個別に補間された式の複雑さを制限します。1 つの式で多くの関数が必要な場合は、ローカル値を使用して、複数の式に分割することを検討してください。
  • 1 行に複数の 3 項演算を含めないでください。代わりに、複数のローカル値を使用してロジックを構築します。

条件値に count を使用する

条件付きでリソースをインスタンス化するには、count メタ引数を使用します。次に例を示します。

variable "readers" {
  description = "..."
  type        = list
  default     = []
}

resource "resource_type" "reference_name" {
  // Do not create this resource if the list of readers is empty.
  count = length(var.readers) == 0 ? 0 : 1
  ...
}

ユーザー指定の変数を使用してリソースの count 変数を設定する際は注意が必要です。このような変数にリソース属性(project_id など)が指定されていて、そのリソースがまだ存在しない場合、Terraform はプランを生成できません。代わりに、Terraform からエラー value of count cannot be computed が返されます。このような場合は、別の enable_x 変数を使用して条件付きロジックを計算します。

反復されるリソースに対して for_each を使用する

入力リソースに基づいてリソースの複数のコピーを作成する場合は、for_each メタ引数を使用します。

モジュールをレジストリに公開する

次のステップ