個人的な備忘録：Terraformを本気で学ぶために、改めてディレクトリ設計について自分なりに調べてみた

## はじめに

Terraformを活用することで、インフラ構成をコードとして管理できるようになり、効率的で再現性の高い運用が可能になります。

:::note info
本記事では、Terraformの設計思想とディレクトリ設計について整理していきます。
:::

そのため、本記事はあくまで個人の備忘録レベルの内容です。***より詳細な情報については、以下の公式ガイドを参考にしてください。***

https://www.terraform.io/

https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/terraform-aws-provider-best-practices/structure.html

## 少し困っていたこと
Terraformを使い始めた当初、どのようにディレクトリを構成すればよいか悩んでいました。

:::note warn
***普段は小規模な個人開発がメインのため、単一のファイルでインフラを構成することが多かったのですが、以前から違和感を感じていました。***
:::

特に、環境ごとに設定を分けるべきか、モジュールをどのように再利用するかなど、ベストプラクティスを理解するのに時間がかかりました。

## Terraformの設計思想について

Terraformの設計思想は、一貫性・再現性・可読性・運用の安全性を重視しており、IaCを実践するうえで非常に強力なツールです。

***過去の記事で詳しくまとめているので、興味のある方はぜひ参考にしてください。***

https://qiita.com/free-honda/items/0f17b61cfeed2c6adf21

## Terraformのディレクトリ設計まとめ
Terraformのディレクトリ設計は、プロジェクトの規模や運用方法によって異なるが、一般的なベストプラクティスとして以下のような構成があるみたいです。

### 1. シンプルな構成（小規模プロジェクト向け）
小規模なプロジェクトや、個人の学習用のTerraform環境では、すべての設定を単一ディレクトリにまとめるシンプルな構成がよく使われます。

```hcl
terraform_project/
│── main.tf        # メインのTerraformコード（リソース定義）
│── variables.tf   # 変数の定義
│── outputs.tf     # 出力情報の定義
│── terraform.tfvars  # 変数の値（環境ごとに管理）
│── provider.tf    # プロバイダー設定（AWS/GCPなど）
│── backend.tf     # 状態管理（State Backend）設定（S3, Terraform Cloudなど）
```

- **適用シーン**: 単純な環境（例: 単一のAWSアカウントでリソースを作成）  
- **メリット**: シンプルで管理しやすい  
- **デメリット**: 規模が大きくなると管理が難しくなる  

### 2. 環境ごとのディレクトリ分割（中規模プロジェクト向け）
開発（dev）、ステージング（stg）、本番（prod）など、環境ごとに異なる設定が必要な場合に適した構成。

```hcl
terraform_project/
│── modules/             # モジュール化された共通リソース
│   ├── vpc/             # VPCのモジュール
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   ├── ec2/             # EC2のモジュール
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│
│── environments/        # 環境ごとの設定
│   ├── dev/             # 開発環境
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   ├── terraform.tfvars
│   ├── stg/             # ステージング環境
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   ├── terraform.tfvars
│   ├── prod/            # 本番環境
│       ├── main.tf
│       ├── variables.tf
│       ├── outputs.tf
│       ├── terraform.tfvars
│
│── backend.tf          # 共通の状態管理（Remote State用）
│── provider.tf         # プロバイダー設定（AWS, GCP, Azureなど）
```

- **適用シーン**: 環境ごとにリソースを分けたい中規模以上のプロジェクト  
- **メリット**:  
  - 環境ごとに管理できる  
  - モジュール化により再利用性が向上  
- **デメリット**:  
  - ディレクトリ構成が複雑になりがち  

### 3. マルチアカウント・マルチリージョン構成（大規模プロジェクト向け）
AWSのOrganizationsを活用したマルチアカウント構成や、異なるクラウドプロバイダーを使用する場合の設計。

```hcl
terraform_project/
│── modules/                   # 共通モジュール
│   ├── network/               # ネットワーク関連
│   ├── compute/               # 計算リソース関連
│   ├── database/              # データベース関連
│
│── accounts/                  # AWSアカウントごとに管理
│   ├── production/            # 本番用AWSアカウント
│   │   ├── us-east-1/         # AWSリージョン別
│   │   │   ├── main.tf
│   │   │   ├── variables.tf
│   │   │   ├── terraform.tfvars
│   │   ├── ap-northeast-1/    # 東京リージョン
│   │   │   ├── main.tf
│   │   │   ├── variables.tf
│   │   │   ├── terraform.tfvars
│   ├── development/           # 開発用AWSアカウント
│   │   ├── us-east-1/
│   │   ├── ap-northeast-1/
│
│── global/                    # グローバル設定（IAM, Route53など）
│   ├── iam/                   # IAMユーザー・ロール
│   ├── dns/                   # Route53の管理
│
│── backend.tf                 # S3, DynamoDBでStateを管理
│── provider.tf                # AWSのプロバイダー設定
```

- **適用シーン**: 大規模な組織や、AWSの複数アカウントを使用するプロジェクト  
- **メリット**:  
  - アカウントごと、リージョンごとに分けることでスケーラビリティが高い  
  - グローバルな設定（IAM、Route53など）を一元管理できる  
- **デメリット**:  
  - 運用が複雑になる  
  - 変更の影響範囲を考慮する必要がある  

## どのディレクトリ構成を選ぶべきか？

| **プロジェクト規模** | **推奨ディレクトリ構成** |
|-----------------|------------------|
| **小規模（個人・PoC）** | シンプルな構成 |
| **中規模（チーム開発）** | 環境ごとのディレクトリ分割 |
| **大規模（企業・マルチアカウント）** | マルチアカウント・マルチリージョン構成 |

Terraformの設計思想に沿ったディレクトリ設計をすることで、管理しやすく、保守性の高いインフラコードを構築できます。

## まとめ
これまでTerraformをキャッチアップし、50個以上のテンプレートを作成してきましたが、改めて設計思想の根幹を復習することで良い学びとなりました。

:::note info
***今後も定期的にTerraformの設計思想やディレクトリ構成を振り返り、理解を深めていきたいと考えています。***
:::

今回の内容はあくまで個人の備忘録ですが、どなたかの学習の参考になれば幸いです。