Terraformの環境の分離について考えてみる

2024/05/16に公開されました。
2024/05/16に更新されました。

TerraformのHCLを管理する上でどのようなディレクトリ構成にすべきかを考えまとめました。


author: kuribo-

はじめに

インフラチームのkuribo-です。
今回はTerraformのコードを管理する上でどのようなディレクトリ構成にすれば良いかを考えまとめてみました。

Terraformって何?

簡単にTerraformの説明です。

TerraformとはHashiCorp社が提供する、IaC(Infrastructure as Code)のツールです。
HCL(HashiCorp Configuration Language)という言語でインフラ構成を記述していきます。

特定のクラウドプロバイダーに依存したツールではなく、利用するクラウドをProviderとしてHCLで宣言することで利用ができます。

Terraformを使うメリットは以下の通りです。

  • インフラをコードとして記述できるのでレビューができるようになります。
  • コードで記述するのでコードを読むことでインフラ構成がわかります。
  • コードを別のプロジェクト向けに修正すれば、同じ構成の別プロジェクトが作成できます。(Dev, Stg, Prdをパラメータだけ変えて作成など)
  • CI/CDに組み込むことでインフラの変更の反映を自動化できます。
  • CI/CDの実行ログから、実行したインフラ構成の変更のログを残せます。(Audit Logsなどでも可能ですが、大量のログから拾うよりCI/CDのログを見た方が楽)

など、私が思いつくメリットを挙げました。
(デメリットもあるにはありますが、メリットが勝っているので導入しない理由にならないです。)

では、次にそのインフラのコードをどのように管理すれば良いか考えます。

前提

  • 各システムには複数のGoogle Cloudのプロジェクト(以下、プロジェクト)があり、環境毎にプロジェクトが分かれる。(Dev, Stg, Prd)
  • 各システムにCommonプロジェクトを作成し、各環境のログやContainer Image、Secret ManagerのSecretなどを保存する。
  • 各システム毎にGithubのリポジトリが作成される。

対応としては以下のような感じ。
1システムに対して、以下のプロジェクトなどのリソースが作成されます。

  • Dev, Stg, Prd環境のプロジェクトが作成される
  • Commonプロジェクトが作成される
  • Githubのリポジトリが作成される

次にこの前提の上でフォルダ構成を考えてみます。

フォルダ構成案

workspace機能を使う場合

まずはWorkspace機能を使ってDev, Stg, Prd環境を切り替える考え方。
Workspaceを使わない場合はStateは全てdefaultに記録されますが、
Workspace機能を使うことで、各Workspace毎にStateが作成されます。
今回はWorkspaceをDev, Stg, Prdとするので、各Stateが作成されます。
ただし、Backend Bucketは1つしか設定できないので各プロジェクトにStateを置くBucketを設置できません。
ですので、CommonプロジェクトにBucketを作成してStateを管理することになります。

フォルダ構成は以下のような感じでしょうか。

.
├── project
│   ├── main.tf
│   └── backend.tf

├── common
│   ├── main.tf
│   └── backend.tf

└-- modules
    ├── service1
    │   ├── output.tf
    │   ├── main.tf
    │   └── varibales.tf

    └-- service2
        ├── output.tf
        ├── main.tf
        └── varibales.tf

メリット

  • Dev, Stg, Prdに全く環境間の差異がない場合は重複してコードを書かなくて良いので最高!

デメリット

  • 環境間で1つでも差異があると途端にめんどくさくなりそう。
  • CI/CDなどにバグがあり、workspace selectを間違えたら、テスト段階のインフラが本番環境に反映されるなどありそう。(コードが分離されていればありえない)

環境毎にフォルダを分ける場合

フォルダを分けてDev, Stg, Prd環境を分離する考え方。
それぞれの環境毎にStateを置くBucketを指定できるので、Stateの設置場所は各プロジェクトになります。

フォルダ構成は以下のような感じでしょうか。
(commonをenvの中に入れるか入れないかは好みかな)

.
├── env
│   ├── dev
│   │   ├── main.tf
│   │   └── backend.tf
│   │
│   ├── stg
│   │   ├── main.tf
│   │   └── backend.tf
│   │
│   └── prd
│       ├── main.tf
│       └── backend.tf

├── common
│   ├── main.tf
│   └── backend.tf

└── modules
    ├── service1
    │   ├── outputs.tf
    │   ├── main.tf
    │   └── varibales.tf

    └── service2
        ├── outputs.tf
        ├── main.tf
        └── varibales.tf

メリット

  • Dev, Stg, Prdがそれぞれ分離しているので、テスト段階のコードをDevだけに書くことが可能。誤ってPrdに反映されることなどもない。
  • 各環境毎に必要なリソースを書ける。(環境毎に差異があっても特に問題ない)

デメリット

  • 各環境毎に同じコードになるため冗長で管理リソースが増えるのと、同じ事を何度も書かなきゃいけない苦痛はある。

まとめの前に

実はGoogle CloudのベストプラクティスではWorkspaceを利用しない方法が書かれています。
https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl=ja#subdirectories

色々考えてましたが、Googleが「環境毎にフォルダを分ける」のをベストプラクティスとしているんですね。
私も2案考えましたが、環境毎にフォルダを分けるほうがメリットが大きいと思いました。

また、HashiCorp側でも同様に、Workspace機能を使って環境を分けるのは適していないと記載があります。
https://developer.hashicorp.com/terraform/cli/workspaces#when-not-to-use-multiple-workspaces
(これを読む限りは、同じ環境を複数作るのにはWorkspaceが使えるということでしょう。Dev1, Dev2みたいな。)

なので、この2つを見る限り環境毎にフォルダを分けるがよさそうという結論になりそうですね。

まとめ

フォルダ構成について考えたり調べたりしてだいぶ纏まりました。
フォルダ構成は環境毎に作成するがベストプラクティスというのが答えで良いのかな。
私自身は、今後もその考え方で環境を分けていきたいですね。

※本記事は、ジーアイクラウド株式会社の見解を述べたものであり、必要な調査・検討は行っているものの必ずしもその正確性や真実性を保証するものではありません。

※リンクを利用する際には、必ず出典がGIC dryaki-blogであることを明記してください。
リンクの利用によりトラブルが発生した場合、リンクを設置した方ご自身の責任で対応してください。
ジーアイクラウド株式会社はユーザーによるリンクの利用につき、如何なる責任を負うものではありません。