※この記事は、Speee Advent Calendar12日目の記事です。
昨日の記事はこちら
お疲れさまです、インフラとCICDを愛するデジタルトランスフォーメーション事業本部開発基盤グループの西田和史(@k_bigwheel)です。最近はGitHub ActionsのWorkflowファイルのCue化を進めています。
本日は、開発基盤グループで採用しているTerraformのディレクトリ構造となぜそうしているのかについて書きたいと思います。
開発基盤グループで採用しているTerraformのディレクトリ構造の例
いきなりですが、うちで採用しているディレクトリ構造の例が以下です。
- /aws
- /system-alpha
- /root-modules
- /production-account
- /account-unique
- /production1
- /staging-account
- /account-unique
- /staging1
- /staging2
- /production-account
- /child-modules
- /account-unique
- /environment-unique
- /root-modules
- /system-alpha
- /gcp
- /system-alpha
- /root-modules
- /production-project
- /project-unique
- /production1
- /staging-project
- /project-unique
- /staging1
- /staging2
- /production-project
- /child-modules
- /project-unique
- /environment-unique
- /root-modules
- /system-alpha
root-modules内のモジュールはchild-modules内のモジュールを参照して内包しています。
例えば aws/system-alpha/root-modules/production-account/production1
は aws/system-alpha/child-modules/environment-unique
を内包する、などです。
ディレクトリ構造ルール
このディレクトリ構造は以下のルールで作られています。
ディレクトリレベル | 分け方 | 例 |
---|---|---|
トップレベル | Terraform Providerの種類1 | aws, gcp, pagerduty |
2ndレベル | プロダクト・システム名 | nurikae, ieul, caresul |
3rdレベル | モジュールの種類 | root-modules, child-modules |
4thレベル | Providerのパーティショニング | awsの本番環境アカウント, awsの検証環境アカウント |
5thレベル | 個別の環境 | 検証環境1, 検証環境2 |
一見、かなり深く掘っているように思えますが、きちんと狙いとメリットがあってこのような構造にしています。
このディレクトリ構造の特徴とメリット
この構造の特徴は3rdレベルの root-modules / child-modules ディレクトリの部分です。
これはterraformのディレクトリ構造の例として最もよく見るmodules / environments型の分け方の問題点を改善するためにこうしました。
modules / environments型の分け方の問題点はシンプルで、environments内にもモジュール(rootモジュール)が含まれているにも関わらず modules or environments という切り口で分類しているために矛盾が発生していることです2。これは、その慣習になれたメンバーだけがterraformディレクトリを操作するのであれば無視できるような問題ですが、アプリケーション開発チームもterraformでインフラを確認・変更するDX事業本部では発生させたくない混乱でした。そのため、明確にどちらかへ分類できる root-modules / child-modules という切り口へ変更しています(参考: 【Terraform】environmentsディレクトリとmodulesディレクトリの構造が微妙な理由 - Qiita)。
その他のディレクトリの分け方のメリットはシンプルなので以下にまとめます:
ディレクトリレベル | 分け方 | メリット |
---|---|---|
トップレベル | Terraform Providerの種類[^1] | 1ルートモジュールに含まれるリソース数を少なくできる = terraform plan / applyの高速化 |
2ndレベル | プロダクト・システム名 | 上に加えて、インフラ境界を明確化できる |
3rdレベル | モジュールの種類 | わかりやすいモジュールの分類方法 |
4thレベル | Providerのパーティショニング | .envrc(direnv)でAWSアカウントごとの環境変数を一元管理できる |
5thレベル | 個別の環境 | 1ルートモジュールに含まれるリソース数を少なくできる |
このディレクトリ構造の特徴とデメリット
root-modules / child-modules 以外のところは一般的に広く使われている方式とそれほど違いがないため大きなデメリットもないのですが、気にしていた点を1つ挙げるとディレクトリ構造が深く、複雑になる点は心配していました。
例えば極めてシンプルなインフラで、
- 本番環境しかない
- ProviderはGCPのみ
- システム1つ
- child-modulesによる共通化なし
な場合でも、
- /gcp
- /system-alpha
- /root-modules
- /production-project
- /production1
- /production-project
- /root-modules
- /system-alpha
のようにディレクトリは5つ深く掘られることになります。 これほど単純な例ではさすがにこの構造を採用するメリットは薄く感じられますが、一方で
- 本番環境と検証環境がある
- ProviderはGCPのみ
- システム1つ
- child-modulesによる共通化なし
のような場合でも
- /gcp
- /system-alpha
- /root-modules
- /production-project
- /production1
- /staging-project
- /staging1
- /production-project
- /root-modules
- /system-alpha
のような構造は取っています。というのは、DX事業本部全体でterraformのディレクトリをこの構造に統一することでエンジニアの認知負荷を下げられるメリットがあるためです。
つまり、懸念してた階層の深さは一定のデメリットはあったもの、DX事業本部全体で統一してこの構造を取ったことによる認知負荷の低減のメリットのほうがかなり大きかったです。そのためシンプルなインフラでもこの構造で統一することにしました。
まとめ
ディレクトリ構造の実践はこんな感じですが、基本的には1ルートモジュールに含まれるリソースを少なくしてterraform作業を効率化すること、開発基盤グループ以外の人が触ってもわかりやすいこと(オレオレ定義を作らず公式な用語をなるべく使うこと)、リポジトリが別でも構造が一貫していることの3点を重要視しています。
この構造はあくまでDX事業本部の例で組織によって最適なディレクトリ構造は変わってくるかもしれませんが、一例として参考になれば幸いです。
最後に
開発基盤グループはインフラやCICDが好き、開発体験の改善が好きで一緒に働いてくれる仲間を募集しています。 興味を持ってくれた方は こちらのForm より連絡ください💁ぜひ私とカジュアル面談しましょう!
他にもSpeeeでは様々なポジションで募集中なので「どんなポジションがあるの?」と気になってくれてた方は、こちらチェックしてみていただければと思います。