Terraformで、どんなディレクトリ構成のパターンがあるか調べる
公式の推奨するモジュールのディレクトリ構成
ディレクトリ構成全体の記事ではないですが、モジュールのディレクトリ構成に限っては、公式ドキュメントに以下のような構成が推奨されています。
$ tree complete-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│ ├── nestedA/
│ │ ├── README.md
│ │ ├── variables.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ ├── nestedB/
│ ├── .../
├── examples/
│ ├── exampleA/
│ │ ├── main.tf
│ ├── exampleB/
│ ├── .../
わりと特徴的だなと思うのは、exampleディレクトリです。モジュールの使い方を示すサンプルコードを配置するディレクトリです。これは、モジュールの利用者がモジュールの使い方を理解しやすくなるため非常に良いアプローチだと思います。また、特定のインフラ構成をモジュール化する際に、そのユースケースに特化した設計を避ける助けにもなります。さらに、多くのリリースに依存しすぎていないかチェックする際の参考にもなります。
Workspaceを用いて環境を分ける
Terraformでは、ワークスペースを使って環境を分けることができます。ワークスペースを使って環境を分けたディレクトリ構成の例です。
terraform-project/
├── main.tf
├── variables.tf
├── outputs.tf
└── modules/
├── app/
├── database/
└── network/
ワークスペースを利用すると、開発・ステージング・本番といった環境を、同じコードベースで管理できます。ワークスペースの切り替えは以下のように行います。
# 新しいワークスペースの作成
terraform workspace new <workspace_name>
# ワークスペースの切り替え
terraform workspace select <workspace_name>
# 現在のワークスペースを確認
terraform workspace show
メリット
- ディレクトリがシンプル
環境別のフォルダが増えず、コードは1つの場所に集約される。 - コード共有が容易
環境によって共通化できるロジックをそのまま使いまわせる。
デメリット
- ステートが同じバックエンドに保存される
S3への権限が、すべての環境で同一になる。 - 環境の切り替え忘れリスク
実行時のワークスペースを選択し間違えると、想定外の環境に対して変更を加えてしまう恐れがある。CI/CDとか使えば間違えなさそう。 - 全環境のことを考える必要がある
ファイルが共通しているためdev環境だけ何かやりたい場合、"dev"をキーにして他の環境には影響がないようにするのかな?
環境ごとにディレクトリを分ける
環境ごとにディレクトリを分ける方法もあります。以下は、環境ごとにディレクトリを分けたディレクトリ構成の例です。
terraform-project/
├── environments/
│ ├── production/
│ │ ├─ main.tf
│ │ ├─ variables.tf
│ │ └─ outputs.tf
│ ├── staging/
│ │ ├─ main.tf
│ │ ├─ variables.tf
│ │ └─ outputs.tf
│ └── development/
│ ├─ main.tf
│ ├─ variables.tf
│ └─ outputs.tf
└── modules/
├── app/
├── database/
└── network/
明示的で良いと思います。ただし、環境ごとにディレクトリを分けることでコードの重複が発生しやすくなる点には注意が必要です。重複が多くなる代わりに、コードと実際の環境が明確になるので良いなーという感じです。
environments
が live
だったりするものも見かけます。共通で使うリソースが出てきたときに environments
だとどこに置くか迷ったりします。
ステートをより細かく分ける
ステートをより細かくするものもあります。
terraform-project/
├── environments/
│ ├── production/
│ │ ├── app/
│ │ ├── database/
│ │ └── network/
│ ├── staging/
│ │ ├── app/
│ │ ├── database/
│ │ └── network/
│ └── development/
│ ├── app/
│ ├── database/
│ └── network/
└── modules/
├── app/
├── database/
└── network/
この場合、環境・モジュール単位でステートファイルが独立するため、万が一のトラブルで特定モジュールのデプロイに失敗しても、他のモジュールには影響が及びにくいというメリットがあります。しかし、リソース間の依存関係をTerraformだけで完結させることが難しくなるため、Terragruntなどを併用して、依存関係を整理しながら運用することが多いです。
まとめ
Terraformのディレクトリ構成にはさまざまなアプローチがあり、チームの規模や運用ポリシー、権限管理の考え方によって最適解が変わります。
- examples/ディレクトリ
モジュールをわかりやすく提供し、利用者にもメリットが大きい。 - ワークスペースを用いる構成
シンプルに同一コードベースで複数環境を扱いたい場合に有効。 - 環境ごとにディレクトリを分ける構成
コードが環境ごとに明確になる一方、重複や共通リソースの扱いに注意が必要。 - さらに細かい単位でステートを分割する構成
障害切り分けや独立性を高められるが、Terraformでの依存管理が難しくなる可能性がある。
Discussion