Terraformはコードをどう配置するかというルールがありません。だからといって自由にコードを書いてしまうと、コードを管理しづらくなったり、メンバーがコードの変更をキャッチアップしづらくなってしまいます。
Terraformのコードを扱うときは、どう管理するかというルールを定めることが大切です。この記事では、Terraformにおけるディレクトリ構成の例を示します。
テクニカルライター。元エンジニア。共著で「現場で使えるRuby on Rails 5」を書きました。プログラミング教室を作るのが目標です。
この記事の目的
この記事の読者の対象はTerraformの基礎を理解している方で、Terraformのコードをどう設計または改善するかについて考えている方です。ディレクトリの構成例にふれることで、プロダクトにあった構造をみつける参考になればと思います。
背景
Terraformはインフラをコードで定義し構築の自動化を行うソフトウェアです。公式なプロバイダでAWSやGCPのリソース定義をできるのはもちろん、コミュニティプロバイダを使うことでSentryやStripeといったサービスの定義も行えます。
Terraformを使うことで、インフラを宣言的に管理できます。バージョン管理を行えば差分がわかりやすくなり、コードを共有するメンバーもキャッチアップしやすくなります。
一方でTerraformを使うサービスや環境、プロバイダやリソースがふえたときに、基準となる指針がないと、コードがちらばりわかりづらくなってしまいます。
再利用できそうな、同じ責務をもつモジュールの存在に気づけないかもしれません。こういった問題を起こさないような、チームにあった指針を決めることが大切になります。
Terraformにおけるディレクトリ構成とは
この記事でいうディレクトリ構成とは「Terraformのコードをどう配置するか」をいいます。main.tf
やvariables.tf
、outputs.tf
などのtfファイルやモジュールの構成をどうするか。サービスや環境の種類をどう定義するか。この課題をディレクトリ構成といいます。
ディレクトリ構成の要件
この記事では、次の要件を満たすディレクトリ構成について示しています。
- メンバーがルールを把握しやすいこと
- コードを変更しやすいこと
- 複数のサービスに対応できること
- 複数の環境に対応できること
- 再利用性があること
この記事の前提
この記事の前提として「Terraformのコードをひとつのチームで管理していること」を想定しています。ひとつのチームで管理しきれない規模になるようであれば、リポジトリを分割するなどの戦略が必要になると思います。
また、TerraformにはWorkspacesというしくみがあります。ただ、この記事ではWorkspacesには言及しません。Workspacesは差分を吸収するためのコードが必要になり、わかりづらくなると考えているためです。
次章でディレクトリ構成を示していますが、これは例にすぎません。最適なディレクトリ構成はサービスの種類やチームの状況によって異なり、ただひとつの正解はないと考えています。重要なのはチーム内で指針をもつことです。チームにあった指針を決めるときの参考になればと思います。
ディレクトリ構成のベストプラクティス
ここではa.example.com
とb.example.com
という2つのサービスがあり、それぞれステージングと本番環境をもっていると想定します。このときのディレクトリ構成を示します。
動作環境
この記事にあるコードは、次のバージョンで動作を確認しています。
名前 | バージョン |
---|---|
Terraform | 0.12.29 |
ディレクトリ構成
まずディレクトリ構成を示し、次節でこの構成をもとにした設計指針を示します。モジュールはAWS S3やHerokuなど、エントリポイントから参照されるものをいくつか示しています。
▼ modules ▼ aws-s3-bucket main.tf outputs.tf variables.tf ▶ heroku ▶ sentry ▶ stripe ▼ services ▼ a.example.com ▼ staging main.tf ▼ production main.tf ▶ b.example.com
ディレクトリ構成の設計指針
上記ディレクトリ構成をもとに、設計指針の例を示します。
- 最小限のモジュールをひとつの単位としてmodules下に配置する。たとえば「S3のバケットをつくる」「HerokuのWeb Dynoを起動する」など。このときバケット名などは変数として定義します。こうすることで再利用性が高まり、各サービスから参照しやすくなります。
- サービスをservices下に、各環境をサービスの下に配置する。たとえば
services/a.example.com/staging
。サービス×環境のエントリポイントがすぐわかります。 - モジュールは3つのtfファイルのみをもつ。
main.tf
とoutputs.tf
、variables.tf
の3つ。これは公式ドキュメントにある最小限の構成で、名前の決め方やファイルのもつ役割がわかりやすくなります。 - エントリポイントにはバックエンドやプロバイダ、モジュール定義のみを行う。できるだけモジュールとして定義し、エントリポイントから使用することで、定義場所のゆらぎがなくなり、再利用性をもたせることができます。
備考
上記のディレクトリ構成例において、a.example.com
とb.example.com
を管理するメンバーが大きく異なる場合はリポジトリをわけた方がよいと思います。
またa.example.com
とb.example.com
で技術スタックが大きく異なる場合もわけた方がよいかもしれません。ステートの規模も分割の基準になると思います。
まとめ
モジュールをわけ、サービス×環境ごとにエントリポイントをもたせるディレクトリ構成例を示しました。この構成にすることでサービスや環境、モジュールがふえても柔軟に対応することができます。
チーム内でディレクトリ構成の設計指針をもつことで、コードを変更するときの指針になり、またキャッチアップしやすくなります。チームにあった構成をみつける参考になればと思います。