Terraformのディレクトリ構成を環境ディレクトリで分けるかたちで見直した
terraformで構築するうえで、どういった構成にするかは割と重要のよう。
まだまだ始めたてではあるものの、最近見直したのでその過程を書いておく。
前提
- Google Cloudのシステム構成をTerraformで管理している
- 環境はステージングと本番とがあり、一旦ステージング環境を構築している
- 開発者は自分のみ
どうなったのか
一部少し迷いはあるけど、現状以下の形に落ち着いている。
├── README.md
├── chile-modules
│   ├── artifact-registry
│   ├── cloudbuild
│   ├── cloudrun
│   └── vpc
├── environments
│   ├── prod
│   └── stg
│       ├── variables.tf
│       └── main.tf
└── secrets
    ├── production.tfvars
    ├── production.tfvars.sample
    ├── staging.tfvars
    └── staging.tfvars.sample
これをプロジェクトルートに infra というディレクトリを作成し中に置いている。
とりあえず触ってみるかというところでmain.tfをinfra直下に置いていたが、環境間でリソースが多少異なりそうなことやtfstateがバッティングしそうなことから環境を分けることにした。
環境を分ける
いくつか見ていたが、Google Cloudが出しているベストプラクティスを参考に environments/ 以下に環境名を作り、そこに格納することにした。
Terraform を使用するためのベスト プラクティス  |  Google Cloud
terraform workspace の形式とかって話を見かけたが、同時にこのコマンドが非推奨なことも見かけた。
環境で切り替える際に何か方法はないかと思って調べていた中でこの話も出てきたが、この構成にするに至った一つの要因なので合わせて書いておく。
おまけ:tfstateはCloud Storageにあげている
tfstateは複数人で開発する際にローカルで持っていると、自分や他人の操作でリソースの作成・削除でトラブルが置きかねないため、Storageで共有しておく(ロックもかかるようにしておく)というのが一般的のよう。なのでCloud Storageで管理するようにした。
resource "random_id" "suffix" {
  byte_length = 4
}
resource "google_storage_bucket" "tfstate_bucket" {
  name          = "tfstate-bucket-${random_id.suffix.hex}"
  location      = var.region
  storage_class = "NEARLINE"
  versioning {
    enabled = true
  }
  lifecycle_rule {
    action {
      type = "Delete"
    }
    condition {
      num_newer_versions = 5
    }
  }
}
terraform {
  backend "gcs" {
    bucket = "tfstate-bucket-ここにランダムなID" # NOTE: ここで変数を使えなかった
  }
}
Cloud Storageは名称がグローバルに一意じゃないといけなかった気がしてこういう方式を取っている。AWS S3だったかもしれない。
一応バージョニングを行いつつ、溜まりすぎても変にコストが掛かるので新しいものを残して自動で削除されるようにした。
環境ごとに分けることについて
今回ステージングと本番とでそこまで大きな差分があるわけでもないが、とりあえず少し出ることが見えているため分けるという選択を取っている。
tfstateの問題も回避できているのと
とはいえ、環境間である程度同じであっていい・あってほしいものもあるのでmodule化をしつつある程度見通しの確保を狙っている。実際はやらないよりはマシという程度の見通し。
module部分のディレクトリ
child-modules/ という分け方を採用してみた。この記事が元ネタ。
【Terraform】environmentsディレクトリとmodulesディレクトリの構造が微妙な理由 #ディレクトリ構造 - Qiita
environments/ で管理しているものもModuleであり、root moduleなのでそれに対してchild-module としておくのが関係がわかりやすいのではないかという話。
なるほどねと思ったので取り込んでみたが、なんとなくroot moduleという名称が分かってはいるもののまだあまり自分の中で浸透していないのでこういう構造になってしまった。
一番中途半端な気がするので現状のモヤモヤである。素直に modules/ でいいかもしれない。
今後やること
もう少しmoduleを上手く使えるように整理したい
現状共通になっていてほしいというところからざっくりmodule化しているが、それが故に少し扱いづらくなっている部分もあるのでそのあたりを整理したい。
変数ファイルの整理
元々plan / applyコマンド実行時に渡す変数を切り替える想定でいたときに名残で変数系のファイルがいくつか残っている。
環境ディレクトリを切り替えた際に使うコマンドのオプションを変えるようにしているが、おそらく未来で間違えるので、できるだけ local を活用して可能性を減らしていきたい。
やってみて
環境ディレクトリを切ったことである意味考えることがでてきたが健全な内容な気がする。また、tfstateの問題も解消することができたのでこれは良かったなと思っている。
とりあえずこの状態でもう少し触って様子を見ていこうと思う。