私のTerraformのディレクトリ設計

[terraform Advent Calendar 2020](https://qiita.com/advent-calendar/2020/terraform)13日目の記事です。  

チーム全体でAWSのメンテナンスを行いながらスキルアップを図りたいと思い、IaCとしてTerraformをつい先日取り入れました。  

その際にTerraform自体のディレクトリ構造やそこに紐づく設計思想などをどうすべきか、各所にて投稿されているベストプラクティスなど色々と調べながら、チームでモブプロをしながらメンテナンスしやすいかなと思う構成にできた気がするので、そちらを記事にします。  

## ディレクトリ構成
以下のような形で作りました  

```
.
├── app_modules
│   ├── auto_scaling
│   │   ├── hoge_service
│   │   │   └── main.tf
│   │   ├── ...
│   │   │   └── ...
│   ├── cloudfront
│   │   └── huga_service
│   │       └── main.tf
│   ├── ec2
│   │   ├── hoge_service
│   │   │   └── main.tf
│   │   └── ...
│   │       └── ...
│   └── ...(ワークロードの各サービスに紐づくAWSサービスのモジュール)
│       └── ...
│           └── ...
├── cloud_modules
│   ├── auto_scaling
│   │   ├── group
│   │   │   └── main.tf
│   │   └── lifecycle_hook
│   │       └── main.tf
│   ├── cloudfront
│   │   ├── distribution
│   │   │   └── main.tf
│   │   └── origin_access_identity
│   │       └── main.tf
│   ├── ec2
│   │   ├── eip
│   │   │   └── main.tf
│   │   ├── instance
│   │   │   └── main.tf
│   │   ├── launch_configuration
│   │   │   └── main.tf
│   │   └── placement_group
│   │       └── main.tf
│   └── ...(AWS各サービスの共通設定)
│       └── ...
│           └── ...
├── env_hugahuga
│   ├── config.tf
│   └── main.tf
└── env_hogehoge
    ├── config.tf
    └── main.tf
```

以下それぞれのディレクトリの内容です。

## envディレクトリ

各環境のエントリーポイントです。  
app_modulesに定義したモジュール群を呼び出して設定していきます。インスタンスタイプやスケール時の設定、ARNなど、環境によって異なる設定をapp_modules側へ渡せるように変数化して、こちらで設定できるようにしています。

```terraform:env_hogehoge/main.tf

...

# for hoge_service settings

module "elb_hoge_service" {
  vpc_id          = var.vpc_id
  subnets         = var.subnets
  security_groups = var.security_groups
  certificate_arn = var.certificate_arn
  source          = "../app_modules/elb/hoge_service"
}

module "ec2_hoge_service" {
  vpc_security_group_ids = var.vpc_security_group_ids
  cluster_name = var.cluster_name
  instance_type          = var.instance_type
  source                 = "../app_modules/ec2/hoge_service"
}

...
```

## cloud_modulesディレクトリ

プロバイダー内（この場合はAWS）の各サービスの基本実装を入れてます。  
cloud_modulesで作ったモジュールをapp_modules側のサービス単位でカスタマイズして利用できるようにします。
cloud_modulesを作る意図としては各サービスにおいての共通設定群を管理するためです。こちらの変更は全app_modulesのサービスに反映されるという想定のため、レビューは特に慎重に実施しています。

```terraform:cloud_modules/ec2/instance/main.tf
...

resource "aws_instance" "example" {
  ami                    = data.aws_ami.default.image_id
  vpc_security_group_ids = var.vpc_security_group_ids
  subnet_id              = var.subnet_id
  key_name               = var.key_name
  instance_type          = var.instance_type
  iam_instance_profile =  var.iam_instance_profile

  tags = {
    Name = var.name
  }
}

...
```

## app_modulesディレクトリ

各AWSサービス単位で切り分けたディレクトリの下にワークロードをサービス単位で切り分けたディレクトリ構成を作りました。cloud_modulesで作った基本実装を読み込んだ上で、各サービス用のカスタマイズを行っています。

```terraform:app_modules/ec2/hoge_service
...

module "module_ec2_launch_configuration_hoge_service" {
  name_prefix     = "${var.env}-module-ec2-hoge_service-"
  cluster_name = var.cluster_name
  security_groups = var.vpc_security_group_ids
  instance_type          = var.instance_type
  key_name = var.key_name

  source = "../../../cloud_modules/ec2/launch_configuration"
}

...

```

それぞれの開発組織・メンバー構成などによってもやりやすい設計があるかと思います。
１つの構成案として誰かの参考になれば幸いです。  
それでは良いクリスマスを