【Terraform】ディレクトリ構成のベストプラクティスを自分なりに探してみた

#はじめに
こんにちは！がーすーです。

3週間ほど前からterraformを使ったインフラ構築のタスクに携わることになりました。
やってみるとなかなか奥が深かったので、記録としてメモに残します。
ちなみにこれまでterraformの経験が０なので、多少目に余る部分があるかとは思いますが、どうぞ気軽にご指摘いただけますと幸いです・・！

#環境
- terraform v0.12.19
- terragrunt v0.23.14
- OCI (Oracle Cloud Infrastructure)
- computeの構築
- production環境 / staging環境が存在
- plan/apply実行は各ディレクトリ毎に行う(compute_stg/prdディレクトリ配下)


#やりたいこと
(1) ☆各computeディレクトリは設定パラメーターファイル(varファイル)のみをもち、moduleが構成ファイル(tfファイル)をもつ

(2) remote-stateからの参照をmodule直下にまとめる

(3) plan/apply実行時に使用したい引数をconstantファイルに定義し、共通ファイルとそれぞれ必要なファイルだけを読み込む


#やりたかったができなかったこと
- providerの設定ファイル共通化とバージョン管理

=> 全く同じ設定値なので、一元化してmoduleに置きたかったがうまくいかず・・
また、terraformのルール上、versionはハードコーディングの必要あり

- terraformバージョン管理ファイルの共通化（調査中）

=> どのディレクトリもversionが一緒なのでうまくまとめたかった（ライブラリ使えばうまくいくかもしれない・・）


#ディレクトリ構成

```
terraform/
├── constant-common.tfvars // どのディレクトリでplan/applyしても必ず呼ばれる
├── constant-compute.tfvars  // computeディレクトリで実行時のみ呼ばれる
├── terragrunt_base.hcl // terragrunt baseファイル
├── modules　　// base module
│   ├── compute-common　　// compute-common module
│   │   ├── compute.tf　　// resourceの定義など
│   │   ├── main.tf
│   │   └── variables.tf
│   ├── output.tf　　// remote stateからの参照ファイル
│   ├── terraform_remote_state.tf　　// remote stateからの参照ファイル
│   └── valuables.tf
├── region1
│       ├── compute_stg
│       │   ├── compute-var.tf　　// 設定パラメータファイル
│       │   ├── main.tf
│       │   ├── provider.tf　　// oci provider
│       │   ├── terraform.tf　　// terraformバージョン管理ファイル
│       │   ├── terragrunt.hcl　　// terragrunt差分ファイル
│       │   └── variables.tf
│       └── compute_prd
│           ├── compute-var.tf
│           ├── main.tf
│           ├── provider.tf
│           ├── terraform.tf
│           ├── terragrunt.hcl
│           └── variables.tf
└── region2
```

### (1) 各computeディレクトリは設定パラメーターファイル(varファイル)のみをもち、moduleが構成ファイル(tfファイル)をもつ

main.tfを伝って渡すことでファイルの分離が可能になります。

※参照先のディレクトリにvariableを定義しておくのを忘れずに

```region1/compute_prd/main.tf

module "compute-common" {
  source = "../../modules/compute-common"

  # constant.tfvarsから受け取った値もここから渡す
  hoge             = var.hoge

  # compute variable
  instance_list = var.instance_list

}

```

```modules/compute-common/variables.tf

# 必須項目でない場合はdefault値を指定してください
variable "instance_list" {}

```

### (2) remote-stateからの参照をmodule直下にまとめる

上記のディレクトリ構成で言うところの`output.tf`、`terraform_remote_state.tf`にあたります。

※各moduleからの参照を忘れずに

```modules/compute-common/main.tf

module "base" {
  source               = "../../modules"
  # baseへ渡したい値があればここに書く
  hoge = var.hoge
}


```

### (3) plan/apply実行時に使用したい引数をconstantファイルに定義し、共通ファイルとそれぞれ必要なファイルだけを読み込む

引数をconstantファイルに定義したら、共通ファイルのみを`terragrunt_base.hcl`で読み込み、差分は各ディレクトリ配下の`terragrunt.hcl`に記載します。

```terragrunt_base.hcl
terraform {
  extra_arguments "common_vars" {
    commands = ["plan", "apply", "destroy", "import"]

    arguments = [
      "-var-file=${get_parent_terragrunt_dir()}/terraform_base.tfvars",
      "-var-file=${get_parent_terragrunt_dir()}/constant-common.tfvars"
    ]
  }
}

```

```region1/compute_prd/terragrunt.hcl
# 差分を記載
terraform {
  extra_arguments "custom_vars" {
    commands = ["plan", "apply", "destroy", "import"]

    arguments = [
      "-var-file=${get_parent_terragrunt_dir()}/constant-compute.tfvars"
    ]
  }
}

# baseを参照する
include {
  path = find_in_parent_folders("terragrunt_base.hcl")
}

```


#その他実現するために必要だったこと
- 各ディレクトリからmoduleに向けてのremote stateの移動

一から構築している場合など人によっては必要ないかと思いますが、moduleにない場合は移動してください。

```
terraform state mv "移動元" "module.${モジュール名}.${インスタンス名}"
```

#EXTRA
### 型定義を行う
terraformは型推論してくれますが、せっかくなのでちゃんと定義しておきます。

```modules/compute-common/variables.tf
variable "instance_list" {
  type = map(object({
    ad                                  = string
    // 中略
  }))
}
```

```region1/compute_prd/compute-var.tf
variable instance_list {
  default = {
    instance1 = {
      ad                                  = "hoge"
      // 中略
    }
  }
}
```


#参考資料
https://www.terraform.io/docs/index.html
https://terragrunt.gruntwork.io/docs/reference/built-in-functions/
https://future-architect.github.io/articles/20190903/