コンテンツにスキップ

Epona Terraform

本ページでは、Eponaが提供するTerraformモジュールを解説します。

Terraformモジュールの設計コンセプト

Eponaでは、2種類のTerraformモジュールを提供します。

  • patternモジュール
  • componentモジュール

Eponaの利用者は、Eponaが提供するTerraformモジュールを使用して環境を構築します。

ℹ️ 前提となるTerraformやProviderのバージョンについては、各patternモジュールのガイドを参照してください。

patternモジュール

Epona利用者が使用する、Terraformモジュールです。Eponaが想定するアクティビティを実現するための基盤となり、patternモジュールの組み合わせにより環境を構築します。

patternモジュールの単位は、例えば以下のようなものになります。具体的なpatternの一覧はこちらを参照してください。

  • 基本的なネットワーク構成
  • CIパイプライン
  • CDパイプライン

patternモジュールの実体は、後述のcomponentモジュールを利用用途に合わせて集約し、抽象度を高めたものです。

componentモジュール

patternモジュールを構成するための部品で、patternモジュールの内部実装の位置づけにあたります。patternを実現するために必要な、基本的なリソース単位でモジュール化されています。

Epona利用者が、componentモジュールを直接利用することは想定していません。

patternモジュールを利用する

インスタンス化

patternモジュールを利用するには、Terraformの構成ファイルに以下のように記述します。

module "[インスタンス名]" {
  source = "git::https://gitlab.com/eponas/epona.git//modules/[適用するpatternモジュールのパス]?ref=[Eponaのバージョン]"

  ...
}

ℹ️ 各モジュールのパスは、それぞれのpatternモジュールのドキュメントを参照してください。

このように、patternモジュールを適用したTerraform構成ファイルからなるリソース定義を「インスタンス」と呼びます。

ℹ️ モジュールをインスタンス化するという表現自体は、Terraformの公式ドキュメントにも記載があります。

たとえば、以下はnetworkパターンを適用しているため、「networkインスタンス」と呼びます。

module "network" {
  source = "git::https://gitlab.com/eponas/epona.git//modules/aws/patterns/network?ref=[Eponaのバージョン]"

  name = "..."
  tags = {...}

  cidr_block = "..."
}

利用者が構築する環境によっては、同じpatternを複数回、利用することもあるでしょう。

たとえば、CDパイプラインのpatternを使い、開発環境用のパイプライン、本番環境用のパイプラインを作成する場合などです。

このように同じpatternから、複数のインスタンスを作成する場合は、インスタンス名を用途に応じた名称で設定します。

モジュールとしてのpatternと、patternを適用したものを「インスタンス」として分けて呼ぶことで、本ドキュメント内で以下のpatternに関する2つの表現を明確に区別できるようにしています。

  • Terraformモジュールとしてのpattern
  • Epona利用者がpatternモジュールを使用して、構築する環境を定義したもの

また、Eponaではインスタンスの単位がTerraformコマンド(planapply等)の実行単位とする方針をとります。

インスタンスの単位を実行単位としているのは、1回のTerraformの実行範囲に多数のリソース定義を含めた場合に発生する、以下のようなことを避けるためです。

  • 定義ファイルの見通しの悪化や、影響範囲の増大
  • 実行時間の長大化

利用するインスタンスには、めったに変更しないもの、運用中にある程度変更が見込まれるものなど、差があるはずです。それにも関わらず、1回のTerraformの実行に含める範囲を大きくしてしまうと確認や実行に時間がかかるようになり、環境も変えづらくなるという事態に陥りやすくなります。

このような事態にならないためにも、実行単位を適切に分割する必要があります。その単位は、インスタンス単位が良いとEponaでは考えます。

ℹ️ 後述のState管理にも関連します。

ディレクトリ構成

Epona利用者は、Delivery環境、Runtime環境それぞれに対して、patternモジュールを利用して環境を定義する必要があります。

この時のディレクトリ構成のイメージを、以下に記載します。

ℹ️ 具体的な例は、Getting Startedを参照してください。

├── setup_terraform_accounts
│   └── delivery
│   └── runtimes
│              ├── [Runtime環境名]
│              └── [Runtime環境名]
├── delivery
│   └── [インスタンス名]
│   │         ├── main.tf
│   │         └── ...
│   └── [インスタンス名]
│   │         ├── main.tf
│   │         └── ...
│   └── ...
│   │
│   └── runtime_instances
│              └── [Runtime環境名]
│              │        ├── [インスタンス名]
│              │        │      ├── main.tf
│              │        │      └── ....tf
│              │        ├── [インスタンス名]
│              │        │      ├── main.tf
│              │        │      └── ....tf
│              │        └── ...
│              │
│              └── [Runtime環境名]
│                        └── ...
└── runtimes
      ├── [Runtime環境名]
      │        ├── [インスタンス名]
      │        │        ├── main.tf
      │        │        └── ....tf
      │        ├── [インスタンス名]
      │        │        ├── main.tf
      │        │        └── ....tf
      │        └── ...
      └── [Runtime環境名]
                └── ...

deliveryは、Delivery環境用のインスタンス定義を収めたディレクトリとなります。runtimesは、Runtime環境用のインスタンス定義を収めたディレクトリとなりますが、Runtime環境は用途に応じて複数環境構成されることを想定しているため、それを踏まえた形となっています。

[Runtime環境名]には、たとえばstagingproductionといった、ステージング環境や本番環境を指す名前が入ります。

またdeliveryディレクトリ配下にあるruntime_instancesディレクトリには、Runtime環境の構築に応じて、Delivery環境へ変更を加えるためのインスタンス定義が収められます。

Terraformのコマンド(planapply等)を実行する際には、各インスタンス名のディレクトリ内で行います。

State管理

Remote State

Terraformの実行単位はインスタンス単位となるため、Terraformが環境に対する変更結果を保存するStateの単位も、インスタンス単位となります。

定義ファイルの見通しや実行時間の観点から、実行単位についての記載をインスタンス化で行いました。一方で、環境は複数人からなるチームでの構築、変更が想定されるため、Stateの管理方針は重要になります。

EponaではTerraformのRemote Stateの考えに則り、以下の内容が実現できるRemote Stateバックエンドを採用します。

  • チーム内での共有
  • 同じインスタンスの同時変更の阻止
  • 秘匿情報の暗号化

ℹ️ TerraformのRemote Stateについては、こちらを参照してください。

Remote Stateバックエンドとしてどのようなストレージを採用するかは、クラウドプロバイダーごとに異なりますので、それぞれのドキュメントで記載しています。

Data SourceとしてのState

Eponaではpatternモジュールの組み合わせで環境を定義しますが、あるpatternインスタンスの実行結果を別のpatternインスタンスの入力として利用することがあります。

たとえば、networkパターンを使用して基本的なネットワーク構成を構築した後に、コンテナオーケストレーションのパターンを適用する場合には配置先のネットワークの情報が必要になります。

このpatternインスタンス間のつなぎ合わせには、StateをData Sourceとして参照することで行います。

以下は、そのイメージになります。

data "terraform_remote_state" "[環境名_インスタンス名]" {
  backend = "..."

  config = {
    ...
  }
}

module "[インスタンス名]" {
  source = "git::https://gitlab.com/eponas/epona.git//modules/[適用するpatternモジュールのパス]?ref=[Eponaのバージョン]"

  argument = data.terraform_remote_state.[環境名_インスタンス名].outputs.[インスタンス名].属性名
}

以下のように、patternを使用したインスタンスとRemote Stateの組み合わせで環境を表現していくのが、Eponaの想定するTerraformモジュールの利用方法です。

  • patternをインスタンス化して組み合わせることで環境を表現する
  • インスタンス間のつなぎ合わせ(情報の受け渡し)は、Data SourceとしてのRemote Stateで行う

他のインスタンスで実行結果を利用できるようにするため、各インスタンスでは使用しているpatternモジュールのOutputを保存するように定義してください。特に理由がなければ、使用しているpatternモジュールのOutputをすべて保存しておくのが良いでしょう。

output "[インスタンス名]" {
  value = module.[インスタンス名]
}

この他、各インスタンス内で独自にリソース定義などを行った場合は、必要に応じてOutputを定義するようにしてください。

ℹ️ 秘匿情報を含むモジュール、リソースを使用している場合は、sensitiveの指定を行い、コンソールに秘匿情報が出力されないようにしましょう。

patternモジュール一覧

Eponaが提供するpatternモジュールについては、各クラウドプロバイダー環境ごとのドキュメントを参照してください。

Eponaのpatternモジュールで不足する場合

Epona利用者が実現したい構成を、Eponaが提供するpatternモジュールだけで完結できるとは限りません。
Eponaがカバーしていないクラウドリソースを使用したくなることもあるでしょう。

このような場合、Epona利用者による独自のモジュール作成が必要になります。
ここでは、独自モジュールを追加する際の考え方を記載します。

基本的には、EponaのTerraformモジュールの設計コンセプトに沿い、Epona利用者独自のpatternモジュールを作成することをおすすめします。

Delivery環境やRuntime環境用の各ディレクトリ内に、直接リソース定義を書いてもよいのでは?という疑問もあるでしょう。
ですが、特にRuntime環境は複数環境となることが多く、各環境で近しい構成を取ることになります。
このような繰り返し使われるユースケースを考えると、独自のpatternモジュールとして作成するのが良いと考えます。
最初は直接リソース定義を書いて試すなどするかもしれませんが、ある単一環境専用のものでなければモジュール化を検討しましょう。

独自のpatternモジュールが必要な場合は、以下のようにEpona利用者が管理するディレクトリ内に、modulesディレクトリを追加します。
このmodulesディレクトリ内に独自のpatternモジュールを配置します。

├── modules  # 独自のモジュールを格納するディレクトリ
│  └── patterns
│      ├── [独自のpattern]
│      │   ├── main.tf
│      │   └── ...
│      ├── ...
│      │
│      │
│      └── [独自のpattern]
│           ├── main.tf
│           └── ...
│
│
├── setup_terraform_accounts
│   └── ...
│
├── delivery
│   ├── [インスタンス名]
│   │         └── ...
│   │         └── ...
│   ├── ...
│   │
│   └── runtime_instances
│              └── [Runtime環境名]
│                        └── ...
└── runtimes
      ├── [Runtime環境名]
      │        ├── [インスタンス名]  # ここでEponaのpatternモジュールや独自のpatternモジュールを使用する
      │        │        ├── main.tf
      │        │        └── ....tf
      │        ├── [インスタンス名]  # ここでEponaのpatternモジュールや独自のpatternモジュールを使用する
      │        │        ├── main.tf
      │        │        └── ....tf
      │        └── ...
      └── [Runtime環境名]
                └── ...

作成した独自のpatternは、以下のようにローカルのモジュールとして参照します。

⚠️ 相対パスの階層は、どのディレクトリから参照するかによって変化することに注意してください。

module "[インスタンス名]" {
  source = "../../../modules/[独自のpattern]"

  ...
}

具体的な例は、Getting Startedを参照するとよいでしょう。

また、pattern内でリソース定義が完結しない場合は独自のcomponentを作成してもよいでしょう。

├── modules
│  ├── patterns
│  │  ├── [独自のpattern]
│  │  │   ├── main.tf
│  │  │   └── ...
│  │  ├── ...
│  │  │
│  │  │
│  │  └── [独自のpattern]
│  │       ├── main.tf
│  │       └── ...
│  │
│  └── components
│       ├── [独自のcomponent]
│       │   ├── main.tf
│       │   └── ...
│       ├── ...
│       │
│       │
│       ├── [独自のcomponent]
│       │   ├── main.tf
│       │   └── ...
│
├── setup_terraform_accounts
│   └── ...
│
├── delivery
│
...

独自のcomponentモジュールを作る場合、ある程度のリソース単位でモジュール化することをおすすめします。
Terraformモジュールの設計コンセプトも参照してください。

具体的な実装としては、Epona自身のソースコードを参考にするとよいでしょう。

また、他の利用者にも使って欲しいpatternモジュールやcomponentモジュールを開発した場合は、ぜひともEponaにContributeしてください。


※ このドキュメントはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。

※ このドキュメントに記載されている会社名、製品名は、各社の登録商標または商標です。

© 2021 TIS Inc.