Speee DEVELOPER BLOG

Speee開発陣による技術情報発信ブログです。 メディア開発・運用、スマートフォンアプリ開発、Webマーケティング、アドテクなどで培った技術ノウハウを発信していきます!

開発基盤グループが採用しているTerraformのディレクトリ構造

※この記事は、Speee Advent Calendar12日目の記事です。
昨日の記事はこちら

tech.speee.jp

お疲れさまです、インフラと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
      • /child-modules
        • /account-unique
        • /environment-unique
  • /gcp
    • /system-alpha
      • /root-modules
        • /production-project
          • /project-unique
          • /production1
        • /staging-project
          • /project-unique
          • /staging1
          • /staging2
      • /child-modules
        • /project-unique
        • /environment-unique

root-modules内のモジュールはchild-modules内のモジュールを参照して内包しています。 例えば aws/system-alpha/root-modules/production-account/production1aws/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

のようにディレクトリは5つ深く掘られることになります。 これほど単純な例ではさすがにこの構造を採用するメリットは薄く感じられますが、一方で

  • 本番環境と検証環境がある
  • ProviderはGCPのみ
  • システム1つ
  • child-modulesによる共通化なし

のような場合でも

  • /gcp
    • /system-alpha
      • /root-modules
        • /production-project
          • /production1
        • /staging-project
          • /staging1

のような構造は取っています。というのは、DX事業本部全体でterraformのディレクトリをこの構造に統一することでエンジニアの認知負荷を下げられるメリットがあるためです。

つまり、懸念してた階層の深さは一定のデメリットはあったもの、DX事業本部全体で統一してこの構造を取ったことによる認知負荷の低減のメリットのほうがかなり大きかったです。そのためシンプルなインフラでもこの構造で統一することにしました。

まとめ

ディレクトリ構造の実践はこんな感じですが、基本的には1ルートモジュールに含まれるリソースを少なくしてterraform作業を効率化すること、開発基盤グループ以外の人が触ってもわかりやすいこと(オレオレ定義を作らず公式な用語をなるべく使うこと)、リポジトリが別でも構造が一貫していることの3点を重要視しています。

この構造はあくまでDX事業本部の例で組織によって最適なディレクトリ構造は変わってくるかもしれませんが、一例として参考になれば幸いです。

最後に

開発基盤グループはインフラやCICDが好き、開発体験の改善が好きで一緒に働いてくれる仲間を募集しています。 興味を持ってくれた方は こちらのForm より連絡ください💁ぜひ私とカジュアル面談しましょう!

他にもSpeeeでは様々なポジションで募集中なので「どんなポジションがあるの?」と気になってくれてた方は、こちらチェックしてみていただければと思います。


  1. 複数のProviderが含まれる場合はメインとなるProviderの名前か、もしくは複合的であることがわかるようなディレクトリ名にする
  2. MECEでない、的な