Only this pageAll pages
Powered by GitBook
1 of 15

日本語 (Japanese)

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Terragrunt

コード構造サンプル

コード構造サンプル

Terraformのコード構造

これらの例ではAWSプロバイダーを使用していますが、例で示された原則の大部分は、他のパブリッククラウドプロバイダーや、DNS、データベース、モニタリングなどの他の種類のプロバイダーにも適用可能です。

タイプ
説明
準備状況

Terragruntコード構造

タイプ
説明
準備状況

小規模

リソースは少数、外部依存なし。単一のAWSアカウント。単一のリージョン。単一の環境。

完了

中規模

複数のAWSアカウントと環境、Terraformを使用した既製のインフラモジュール。

完了

大規模

多数のAWSアカウントと複数のリージョン、コピーペーストの削減が急務、カスタムインフラモジュール、コンポジションの多用。Terraformを使用。

進行中

超大規模

複数のプロバイダー(AWS、GCP、Azure)。マルチクラウド展開。Terraformを使用。

未着手

中規模

複数のAWSアカウントと環境、既製のインフラモジュール、Terragruntを用いたコンポジションパターン。

未着手

大規模

多数のAWSアカウントと複数のリージョン、コピーペーストの削減が急務、カスタムインフラモジュール、コンポジションの多用。Terragruntを使用。

未着手

超大規模

複数のプロバイダー(AWS、GCP、Azure)。マルチクラウド展開。Terragruntを使用。

未着手

Terraform

概念

公式のTerraformドキュメントには、設定のすべての側面が詳細に説明されています。次のセクションを理解するために、注意深くお読みください。 このセクションでは、本書で使用される重要な概念について説明します。

リソース

リソースとは、aws_vpcやaws_db_instanceなどを指します。リソースはプロバイダーに属し、引数を受け取り、属性を出力し、ライフサイクルを持っています。リソースは作成、取得、更新、削除が可能です。

リソースモジュール

リソースモジュールは、相互に接続されたリソースの集まりで、共通のアクションを実行します(例:は、VPC、サブネット、NATゲートウェイなどを作成します)。プロバイダー設定に依存し、それはモジュール内またはより上位の構造(例:インフラモジュール)で定義できます。

インフラモジュール

インフラモジュールは、リソースモジュールの集まりで、論理的には接続されていない場合もありますが、現在の状況やプロジェクト、設定において同じ目的を果たします。プロバイダーの設定を定義し、それが下位のリソースモジュールやリソースに渡されます。通常、論理的な区切りごと(例:AWSリージョン、Googleプロジェクト)に1つのエンティティで機能するよう制限されています。

例えば、 モジュールは、 や のようなリソースモジュールを使用して、 上で を実行するために必要なインフラを管理します。

もう一つの例は、 モジュールです。ここでは、複数の によるモジュールが一緒に使用され、インフラを管理するとともに、Dockerリソースを使用してDockerイメージをビルド、プッシュ、デプロイします。すべてが一つのセットで実行されます。

コンポジション

コンポジションとは、複数のインフラモジュールの集まりで、複数の論理的に分離された領域(例:AWSリージョン、複数のAWSアカウント)にまたがることができます。コンポジションは、組織全体やプロジェクト全体に必要なインフラを記述するために使用されます。

コンポジションはインフラモジュールで構成され、そのモジュールはリソースモジュールで構成され、リソースモジュールは個々のリソースを実装しています。

データソース

データソースは読み取り専用の操作を実行し、プロバイダー設定に依存しています。リソースモジュールやインフラストラクチャモジュールで使用されます。

データソースterraform_remote_stateは、上位レベルのモジュールやコンポジションを結びつける役割を果たします。

を使用すると、外部プログラムがデータソースとして機能し、Terraformの設定内で他の場所で使用する任意のデータを提供できます。以下は、モジュールの例で、外部のPythonスクリプトを呼び出してファイル名を計算しています。

データソースは、指定されたURLに対してHTTP GETリクエストを行い、レスポンスに関する情報をエクスポートします。これは、ネイティブなTerraformプロバイダーが存在しないエンドポイントから情報を取得する際に便利です。

リモートステート

インフラモジュールやコンポジションは、をリモートの場所に保存し、他のユーザーが制御可能な方法で取得できるようにするべきです(例:ACLの指定、バージョニング、ロギングの設定)。

プロバイダー、プロビジョナーなど

プロバイダーやプロビジョナー、その他いくつかの用語については公式ドキュメントで非常に詳しく説明されており、ここで繰り返す必要はありません。私の意見では、これらは良いTerraformモジュールを書くことにあまり関係がないと考えています。

なぜ難しいのか?

個々のリソースがインフラの「原子」のようなものである一方、リソースモジュールは「分子」(原子から構成される)に相当します。モジュールは、バージョン管理され共有可能な最小の単位です。特定の引数リストがあり、この単位に必要な機能を実行するための基本的なロジックが実装されています。例えば、モジュールは、入力に基づいてaws_security_groupやaws_security_group_ruleリソースを作成します。このリソースモジュール自体は、他のモジュールと組み合わせてインフラストラクチャモジュールを作成するために使用できます。

「分子」(リソースモジュールやインフラモジュール)間でのデータアクセスは、モジュールのアウトプットやデータソースを使って行います。

コンポジション間のアクセスは、リモートステートデータソースを使用することが多いです。あります。

上記の概念を擬似的な関係に当てはめると、次のようになります。

ようこそ

このドキュメントでは、Terraformのベストプラクティスを体系的に説明し、Terraformユーザーが最も頻繁に経験する問題に対する推奨事項を提供します。

Terraformは非常に強力(現在では最も強力なものかもしれません)で、インフラをコードとして管理できるツールの中でも最も広く使用されています。開発者に多くのことを可能にし、サポートや統合が困難になる方法で作業することを制限しません。

本書で説明されている情報の一部は、ベストプラクティスとは見えないかもしれません。そのため、読者が確立されたベストプラクティスと単なる一つの意見に基づくやり方を区別できるように、時折ヒントを使って文脈を提供し、各サブセクションに関連するベストプラクティスの成熟度レベルを示すアイコンを使用しています。

本書は2018年、晴れたマドリードで書き始められ、無料で以下のサイトから入手可能です: https://www.terraform-best-practices.com/

数年後、Terraform 1.0で利用可能な最新のベストプラクティスで更新されました。最終的には、Terraformユーザーにとって疑いのないベストプラクティスと推奨事項のほとんどを本書に収めることを目指しています。

出資

Please contact me if you want to become a sponsor.

言語

他言語への翻訳にご協力いただける方はご連絡ください。

コントリビューション

常にフィードバックを求め、この本をコミュニティの成熟や新しいアイデアの実装・検証に応じて更新していきたいと考えています。

特定のトピックに興味がある場合は、を立てるか、取り上げてほしいリクエストに「いいね」をしてください。また、コンテンツを提供したい場合は、ドラフトを書いてプルリクエストを送ってください(現時点で文章の完成度を気にする必要はありません!)。

著者

この本は、 と様々な寄稿者や翻訳者の協力によって管理されています。

ライセンス

この作品はApache 2ライセンスの下で提供されています。詳細はLICENSEをご確認ください。

このコンテンツの著者および寄稿者は、ここで提供される情報の正確性を保証するものではありません。ここで提供される情報は自由に提供されており、このコンテンツやプロジェクトに関わるいかなる人との間にも、契約や合意が成立しないことをご理解ください。 著者および寄稿者は、このコンテンツに含まれる、関連する、またはリンクされている情報の誤りや不足に起因して、いかなる当事者に生じた損失、損害、または混乱に対しても一切の責任を負わないことをここに明記します。これには、過失、事故、その他の理由に起因する誤りや不足が含まれます。

Copyright © 2018-2023 Anton Babenko.

コード構造

Terraformのコード構造に関する質問は、コミュニティで最も頻繁に見られるものです。誰もが一度はプロジェクトの最適なコード構造について考えたことがあるでしょう。

Terraformの設定はどのように構造化すべきでしょうか?

これは多くの解決策が存在する質問の一つであり、普遍的なアドバイスを提供することは非常に難しいため、まず私たちが扱っているものを理解することから始めましょう。

  • プロジェクトの複雑さはどの程度ですか?

関連するリソースの数

  • Terraformプロバイダーの数 (下記の「論理的なプロバイダー」に関する注記を参照)

  • インフラの変更頻度は?

    • 月1回/週1回/1日1回

    • 継続的 (新しいコミットがある度に毎回)

  • 誰がコードを変更しますか? 新しいアーティファクトがビルドされた時にCIサーバーがリポジトリを更新することを許可していますか?

    • 開発者のみがインフラのリポジトリにプッシュ可能

    • 誰でも(CIサーバー上で実行される自動化されたタスクを含む)PRをオープンすることで何かしらの変更を提案可能

  • どのデプロイメントプラットフォームまたはデプロイメントサービスを使用していますか?

    • AWS CodeDeploy、Kubernetes、OpenShiftは少し異なるアプローチが必要

  • 環境はどのようにグループ化されていますか?

    • 環境、リージョン、プロジェクトごと

  • 論理的なプロバイダーはTerraformのロジック内だけで完全に動作し、他のサービスとの相互作用はほとんどありません。そのため、その複雑さはO(1)として考えることができます。最も一般的な論理的なプロバイダーには、random、local、terraform、null、time などがあります。

    Terraformの設定の構造化を始めるにあたって

    すべてのコードを main.tf に配置することは、初めて始める時やサンプルコードを書く時には良い方法です。それ以外の場合は、以下のように論理的に複数のファイルに分割する方が良いでしょう:

    • main.tf - モジュール、ローカル変数、データソースを呼び出してすべてのリソースを作成します

    • variables.tf - main.tfで使用される変数の宣言を含みます

    • outputs.tf - main.tfで作成されたリソースからの出力を含みます

    • versions.tf - Terraformとプロバイダーのバージョン要件を含みます

    terraform.tfvars は、 composition 以外では使用すべきではありません。

    Terraformの設定構造についての考え方

    以下の例で使用される主要な概念の resource module、infrastructure module、 composition を必ず理解してください。

    コードを構造化するための一般的な推奨事項

    • より少ないリソース数で作業する方が容易で速い

      • terraform planと terraform apply はともに、リソースの状態を確認するためにクラウドAPIを呼び出します

      • インフラ全体を単一の構成にまとめると時間がかかる可能性がある

    • セキュリティ侵害時の影響範囲はリソースが少ない方が小さい

      • 関連のないリソースを別々の構成に配置することで、問題が発生した場合のリスクを軽減

    • プロジェクトはリモートステートを使用して開始してください。その理由は:

      • あなたのラップトップは、インフラの信頼できる情報源として適切な場所ではありません

      • gitでtfstateファイルを管理することは悪夢のようなものです

      • 後にインフラレイヤーが複数の方向(依存関係やリソースの数)に成長した時、制御しやすい

    • 一貫した構造と規則を実践してください

      • 手続き型コードと同様に、Terraformコードは最初に人が読むことを考えて書かれるべきです。一貫性があれば、6ヶ月後に変更が必要になった時に役立ちます

      • Terraformステートファイル内でリソースを移動することは可能ですが、構造や命名に一貫性がない場合、移動が困難になる可能性があります

    • リソースモジュールはできるだけシンプルに保ってください

    • 変数として渡せる値や、データソースを使用して検出できる値は、ハードコードしないでください

    • データソースと terraform_remote_state は、特に構成内のインフラモジュール間の「接着剤」として使用してください

    本書では、サンプルプロジェクトが複雑さによって小規模から大規模インフラまでグループ分けされています。この区分は厳密なものではないので、他の構造も確認してください。

    インフラモジュールと構成のオーケストレーション

    小規模なインフラストラクチャとは、依存関係が少なく、リソースも少ないことを意味します。プロジェクトが成長するにつれて、Terraformの設定の実行を連鎖させ、異なるインフラストラクチャモジュールを接続し、構成内で値を受け渡す必要性が明らかになってきます。

    開発者が使用するオーケストレーションソリューションには、少なくとも5つの異なるグループがあります:

    1. Terraformのみ:非常に直接的なアプローチで、開発者は仕事を完了するためにTerraformだけを知って必要があります。

    2. Terragrunt:インフラ全体のオーケストレーションと依存関係の処理が可能な純粋なオーケストレーションツールです。Terragruntはインフラストラクチャモジュールと構成をネイティブに扱うため、コードの重複を減らすことができます。

    3. 自社開発スクリプト:多くの場合、これはオーケストレーションへの最初のステップとして、Terragruntを発見する前に行われます。

    4. Ansibleやそれに類似する汎用自動化ツール:通常、TerraformがAnsible採用後に導入される場合や、Ansible UIが積極的に使用される場合に使用されます。

    5. やその他のKubernetesに触発されたソリューション:Kubernetesエコシステムを活用し、reconciliation loop機能を使用してTerraform設定の望ましい状態を達成することが意味を持つ場合があります。詳細については、「 」 の動画を参照

    これを踏まえて、本書では最初の2つのプロジェクト構造、TerraformのみとTerragruntについて検討します。

    次の章で Terraform または Terragrunt のコード構造の例を確認してください。

    AWS VPC Terraformモジュール
    terraform-aws-atlantis
    terraform-aws-vpc
    terraform-aws-security-group
    AWS Fargate
    Atlantis
    terraform-aws-cloudquery
    terraform-aws-modules
    外部データソース
    terraform-aws-lambda
    http
    Terraformの状態(Terraform state)
    terraform-aws-security-group
    設定間でデータを共有する方法は複数
    Simple infrastructure composition

    Compliance.tf — Terraform Compliance Simplified. Make your Terraform modules compliance-ready.

    —

    issue
    Anton Babenko
    العربية (Arabic)
    Bosanski (Bosnian)
    Português (Brazilian Portuguese)
    English
    Français (French)
    ქართული (Georgian)
    Deutsch (German)
    ελληνικά (Greek)
    עברית (Hebrew)
    हिंदी (Hindi)
    Bahasa Indonesia (Indonesian)
    Italiano (Italian)
    ಕನ್ನಡ (Kannada)
    한국어 (Korean)
    Polski (Polish)
    Română (Romanian)
    简体中文 (Simplified Chinese)
    Español (Spanish)
    Türkçe (Turkish)
    Українська (Ukrainian)
    اردو (Urdu)

    Terraformを使用した大規模インフラ

    ソース:

    この例は、大規模インフラストラクチャ向けのTerraform構成を整理するコード例で、以下の内容を使用しています。

    • 2つのAWSアカウント

    • 2つのリージョン

    • 2つの独立した環境(プロダクションとステージング、共有は一切なし)。各環境は異なるAWSアカウント内にあり、2つのリージョン間でリソースを展開する

    Terraform 設定ファイルの記述

    locals を使用してリソース間の明示的な依存関係を指定する

    リソースの直接的な依存関係がTerraformの構成にない場合でも、Terraformに対していくつかのリソースを削除すべきことを示すための便利な方法です。

    composition-1 {
      infrastructure-module-1 {
        data-source-1 => d1
    
        resource-module-1 {
          data-source-2 => d2
          resource-1 (d1, d2)
          resource-2 (d2)
        }
    
        resource-module-2 {
          data-source-3 => d3
          resource-3 (d1, d3)
          resource-4 (d3)
        }
      }
    }
    命名
    Crossplane
    Crossplane vs Terraform

    各環境は、Terraform Registryから取得した既製のインフラモジュール(alb)の異なるバージョンを使用

  • 各環境は、ローカルディレクトリから取得される内部モジュールmodules/networkの同じバージョンを使用

  • ここで説明するような大規模プロジェクトでは、Terragruntを使用する利点が非常に明確になります。Terragruntのコード構造例をご覧ください。

    • インフラが論理的に分離されているプロジェクトに最適(AWSアカウントが分かれている場合)

    • AWSアカウント間で共有されるリソースを変更する必要がない場合に適している(一つの環境=一つのAWSアカウント=一つの状態ファイル)

    • 環境間での変更のオーケストレーションが不要な場合に適している

    • 環境ごとにインフラリソースが異なり、一般化できない場合に適している(例:ある環境またはリージョンに存在しないリソースがある場合)

    プロジェクトが成長するにつれ、これらの環境を互いに最新の状態に保つことが難しくなります。繰り返し行われるタスクには、既製または内部のインフラモジュールの使用を検討してください。

    https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/large-terraform
    Terraform 0.12 - Required 引数 vs Optional 引数
    1. var.website が空のマップでない場合は、Required引数である index_document が設定されている必要があります。

    2. Optional引数の error_document は省略可能です。

    https://raw.githubusercontent.com/antonbabenko/terraform-best-practices/master/snippets/locals.tf
    main.tf
    variable "website" {
      type    = map(string)
      default = {}
    }
    
    resource "aws_s3_bucket" "this" {
      # omitted...
    
      dynamic "website" {
        for_each = length(keys(var.website)) == 0 ? [] : [var.website]
    
        content {
          index_document = website.value.index_document
          error_document = lookup(website.value, "error_document", null)
        }
      }
    }
    terraform.tfvars
    website = {
      index_document = "index.html"
    }

    FAQ

    FTP (Frequent Terraform Problems)

    使用を検討すべきツールは何ですか?

    • Terragrunt - オーケストレーションツール

    • - コードリンター

    • - バージョンマネージャー

    • - バージョンマネージャー用のHashiCorpプラグイン

    • - プルリクエストの自動化

    • - で使用するTerraform用のGitフックコレクション

    • - プルリクエストでのTerraformのクラウドコスト見積もり。Terragrunt、Atlantis、pre-commit-terraformとも連携可能。

    モジュールのに対する解決策は何ですか?

    リソースとインフラモジュールのバージョンは指定されるべきです。プロバイダーはモジュールの外部で、コンポジション内でのみ設定されるべきです。プロバイダーとTerraformのバージョンもロックすることができます。

    マスターとなる依存関係管理ツールは存在しませんが、依存関係の指定をより問題の少ないものにするためのヒントがいくつかあります。例えば、を使用して依存関係の更新を自動化することができます。Dependabotは、依存関係を安全かつ最新の状態に保つためのプルリクエストを作成します。DependabotはTerraformの設定をサポートしています。

    Terraformを使用した小規模インフラ

    ソース: https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/small-terraform

    この例には、外部依存がない小規模インフラストラクチャのためのTerraform構成を整理するコードが含まれています。

    • 初めての導入や進めながらのリファクタリングに最適

    • 小規模なリソースモジュールに最適

    • 小規模かつ直線的なインフラストラクチャモジュールに適している(例: )

    • リソースが少ない(20〜30未満)の場合に適している

    すべてのリソースに対して単一の状態ファイルを使用すると、リソースが増え、Terraformの操作が遅くなる可能性があります(-target引数を使ってリソース数を制限することを検討してください)

    Terraformを使用した中規模インフラ

    ソース:

    この例は、中規模インフラストラクチャのためのTerraform構成を整理するコード例で、次の内容を使用しています。

    • 2つのAWSアカウント

    • 2つの独立した環境(プロダクションとステージング、共有は一切なし)。各環境は異なるAWSアカウント内に存在する

    • 各環境は、から取得した既製のインフラモジュール(ALB)の異なるバージョンを使用

    tflint
    tfenv
    asdf-hashicorp
    asdf
    Atlantis
    pre-commit-terraform
    pre-commitフレームワーク
    Infracost
    ディペンデンシーヘル
    Dependabot
    terraform-aws-atlantis

    各環境は、ローカルディレクトリから取得される内部モジュールmodules/networkの同じバージョンを使用

    • インフラが論理的に分離されているプロジェクトに最適(AWSアカウントが分かれている場合)

    • AWSアカウント間で共有されるリソースを変更する必要がない場合に適している(一つの環境=一つのAWSアカウント=一つの状態ファイル)

    • 環境間での変更のオーケストレーションが不要な場合に適している

    • 環境ごとにインフラリソースが異なり、一般化できない場合に適している(例:ある環境またはリージョンに存在しないリソースがある場合)

    プロジェクトが成長するにつれ、これらの環境を互いに最新の状態に保つことが難しくなります。繰り返し行われるタスクには、既製または内部のインフラモジュールの使用を検討してください。

    https://github.com/antonbabenko/terraform-best-practices/tree/master/examples/medium-terraform
    Terraform Registry

    コーディングスタイル

    • 例やTerraformモジュールには、機能と使用方法を説明するドキュメントを含める必要があります。

    • README.mdファイル内のすべてのリンクは絶対Pathにし、Terraform Registryのウェブサイトで正しく表示されるようにします。

    • ドキュメントには、で作成した図やで作成した設計図を含めることができます。

    • Terraformのプリコミットフック()を使用して、コードが正しく、適切にフォーマットされ、自動的にドキュメント化されるようにし、Gitにプッシュされる前に確認できるようにしてください。

    ドキュメンテーション

    ドキュメントの自動生成

    は、マルチランゲージのプリコミットフックを管理および維持するためのフレームワークです。Pythonで書かれており、コードがGitリポジトリにコミットされる前に、開発者のマシン上で自動的に何かしらの処理を行うための強力なツールです。通常は、リンターを実行したり、コードをフォーマットしたりするために使用されます(を参照)。

    Terraformの構成では、pre-commitを使用してコードをフォーマットし、検証し、ドキュメントを更新することができます。

    をチェックして、使い方を把握し、すでに使用されている既存のリポジトリ(例:)を確認してください。

    terraform-docs

    は、さまざまな出力形式でTerraformモジュールからドキュメントを生成するツールです。手動で実行することもできます(プリコミットフックなしで)、または を使用してドキュメントを自動的に更新することもできます。

    @todo: モジュールのバージョン、リリース、GHアクションを文書化する

    参照

    1. Blog post by :

    mermaid
    cloudcraft.co
    Terraform pre-commit hooks
    pre-commit
    サポートされているフック
    pre-commit-terraformリポジトリ
    terraform-aws-vpc
    terraform-docs
    pre-commit-terraform hooks
    pre-commit framework homepage
    Collection of git hooks for Terraform to be used with pre-commit framework
    Dean Wilson
    pre-commit hooks and terraform - a safety net for your repositories

    ワークショップ

    ワークショップ

    このガイドで説明されている内容を練習したい人のためのワークショップもあります。

    コンテンツはこちらから - https://github.com/antonbabenko/terraform-best-practices-workshop

    参考文献

    Terraformコミュニティに関連する素晴らしいコンテンツやオープンソースプロジェクトを作成・管理している人々は大勢いますが、awesome-terraformのような既存のコレクションをコピーすることなく、これらのリンクを掲載するための最適な構造を考えるのは難しいです。

    https://twitter.com/antonbabenko/lists/terraform-experts - Terraformを非常に活発に使用しており、尋ねると多くのことを教えてくれる人々のリスト

    https://github.com/shuaibiyy/awesome-terraform - HashiCorpのTerraformに関するキュレーションされたリソースのリスト

    http://bit.ly/terraform-youtube - Anton Babenkoによる"Your Weekly Dose of Terraform"というYouTubeチャンネル。レビュー、インタビュー、Q&A、ライブコーディング、そしてTerraformを使用したハッキングなどのライブストリームを提供しています。

    https://weekly.tf - Anton Babenkoによる"Terraform Weekly"ニュースレター。Terraformの世界における様々なニュース(プロジェクト、アナウンス、ディスカッション)を提供しています。

    命名規則

    一般的な規則

    少なくともこれらの規則には従うべきですよ :)

    クラウドリソースの実際の名前には、多くの場合、使用可能な名前に制限があることに注意してください。例えば、一部のリソースではダッシュ(-)を含めることができなかったり、キャメルケースでなければならなかったりします。本書で説明する規則は、Terraform自体の名前に関するものです。

    1. リソース名、データソース名、変数名、出力など、すべての場所で -(ダッシュ)の代わりに _(アンダースコア)を使用してください。

    2. UTF-8がサポートされていても、小文字とアルファベットを使用することを推奨します。

    リソースとデータソースの引数

    1. リソース名にリソースタイプを(部分的にも、完全にも)繰り返さないでください:

    1. より説明的で一般的な名前が利用できない場合、またはリソースモジュールがこのタイプのリソースを1つだけ作成する場合(例えば、では aws_nat_gateway タイプのリソースは1つだけで、aws_route_table タイプのリソースは複数あるため、aws_nat_gateway は this という名前にし、aws_route_table には private、public、database のようなより説明的な名前をつけるべき)、リソース名は this にすべきです。

    resourceのコード例

    countとfor_eachの使用方法

    tags の配置

    count内の条件

    変数

    1. リソースモジュールで車輪の再発明をしないでください:作業しているリソースの "Argument Reference" セクションで定義されている通りに、変数のname、description、default値を使用してください。

    2. 変数のバリデーションサポートはかなり限定的です(例:他の変数へのアクセスや参照ができません)。多くの場合この機能は役に立たないので、それを考慮して計画してください。

    3. 型がlist(...)またはmap(...)

    出力

    出力はスコープ外でも一貫性があり理解しやすいものにしてください(モジュールを使用するユーザーにとって、返される値の型と属性が明らかであるべきです)。

    1. 出力名は、含まれるプロパティを説明するものであり、通常望むよりも自由度は低くすべきです。

    2. 出力名の良い構造は{name}_{type}_{attribute}のようになります。ここで:

      1. {name}はリソースまたはデータソース名です

    outputのコード例

    セキュリティグループのIDを最大1つ返す場合:

    同じタイプの複数のリソースがある場合、出力名ではthisを省略すべきです:

    返される値がリストの場合は、複数形の名前を使用してください

    名前には常に単数名詞を使用してください。

  • 引数の値の中や、人が目にする場所(例:RDSインスタンスのDNS名)では、-(ハイフン)を使用してください。

  • リソースまたはデータソースのブロック内で、count/for_each引数を最初の引数として一番上に記述し、その後に改行を入れて区切ってください。

  • リソースでサポートされている場合はtags引数を実質的な最後の引数として記述し、必要に応じてその後にdepends_onとlifecycleを続けてください。これらはすべて空行1行で区切ってください。

  • count/for_each引数で条件を使用する場合は、lengthやその他の式を使用するのではなく、ブール値を使用することを推奨します。

  • の場合は、変数名に複数形を使用してください。
  • 変数ブロック内のキーは次の順序で並べてください:description、type、default、validation

  • 明白だと思える場合でも、将来必要になるので、すべての変数に必ずdescriptionを含めてください。

  • 各キーに厳密な制約が必要な場合を除き、object()のような特定の型よりも、シンプルな型(number、string、list(...)、map(...)、any)の使用を推奨します。

  • マップのすべての要素が同じ型(例:string)を持つ場合、または変換可能な場合(例:number型はstringに変換可能)は、map(map(string))のような特定の型を使用してください。

  • 特定の深さから型バリデーションを無効にする場合や、複数の型をサポートする必要がある場合は、any型を使用してください。

  • 値{}は時にマップであり、時にオブジェクトです。オブジェクトを作成する方法がないため、マップを作成するにはtomap(...)を使用してください。

  • data "aws_subnet" "private"の{name}はprivateです

  • resource "aws_vpc_endpoint_policy" "test"の{name}はtestです

  • {type}はプロバイダーのプレフィックスを除いたリソースまたはデータソースの型です

    • data "aws_subnet" "private"の{type}はsubnetです

    • resource "aws_vpc_endpoint_policy" "test"の{type}はvpc_endpoint_policyです

  • {attribute}は出力によって返される属性です

  • 例を参照してください。

  • 出力が補間関数と複数のリソースを使用した値を返す場合、{name}と{type}はできるだけ一般的にすべきです(プレフィックスとしてのthisは省略すべき)。例を参照してください。

  • 返される値がリストの場合は、複数形の名前にすべきです。例を参照してください。

  • 明白だと思える場合でも、すべての出力に必ずdescriptionを含めてください。

  • すべてのモジュールのすべての場所でその出力の使用を完全に制御できない限り、sensitive引数の設定は避けてください。

  • (0.13以前のバージョンでの従来のアプローチである)element(concat(...))よりも(Terraform 0.13以降で利用可能な)try()を推奨します。

  • AWS VPCモジュール
    `resource "aws_route_table" "public" {}`
    `resource "aws_route_table" "public_route_table" {}`
    `resource "aws_route_table" "public_aws_route_table" {}`
    main.tf
    resource "aws_route_table" "public" {
      count = 2
    
      vpc_id = "vpc-12345678"
      # ... 残りの引数は省略
    }
    
    resource "aws_route_table" "private" {
      for_each = toset(["one", "two"])
    
      vpc_id = "vpc-12345678"
      # ... 残りの引数は省略
    }
    main.tf
    resource "aws_route_table" "public" {
      vpc_id = "vpc-12345678"
      count  = 2
    
      # ... 残りの引数は省略
    }
    main.tf
    resource "aws_nat_gateway" "this" {
      count = 2
    
      allocation_id = "..."
      subnet_id     = "..."
    
      tags = {
        Name = "..."
      }
    
      depends_on = [aws_internet_gateway.this]
    
      lifecycle {
        create_before_destroy = true
      }
    }   
    main.tf
    resource "aws_nat_gateway" "this" {
      count = 2
    
      tags = "..."
    
      depends_on = [aws_internet_gateway.this]
    
      lifecycle {
        create_before_destroy = true
      }
    
      allocation_id = "..."
      subnet_id     = "..."
    }
    outputs.tf
    resource "aws_nat_gateway" "that" {    # 最適
      count = var.create_public_subnets ? 1 : 0
    }
    
    resource "aws_nat_gateway" "this" {    # 良い
      count = length(var.public_subnets) > 0 ? 1 : 0
    }
    outputs.tf
    output "security_group_id" {
      description = "The ID of the security group"
      value       = try(aws_security_group.this[0].id, aws_security_group.name_prefix[0].id, "")
    }
    outputs.tf
    output "this_security_group_id" {
      description = "The ID of the security group"
      value       = element(concat(coalescelist(aws_security_group.this.*.id, aws_security_group.web.*.id), [""]), 0)
    }
    outputs.tf
    output "rds_cluster_instance_endpoints" {
      description = "A list of all cluster instance endpoints"
      value       = aws_rds_cluster_instance.this.*.endpoint
    }