Terraformを利用したプロジェクトのディレクトリ構成とworkspaceの使い方

Terraformを利用したプロジェクトのディレクトリ構成とworkspaceの使い方

こんにちは。 インフラエンジニアの久保です。

今回は、弊社で利用しているTerraformのディレクトリ構成について紹介します。
現在、Terraformを利用しているタイトルが複数存在します。
ただし、ワールド制の違いやマルチリージョン展開しているなど、プロジェクトによって要件が異なるため、それに合わせてリソース管理方法を変化させています。
Terraformのディレクトリの切り方やtfstateの管理については、皆さんも苦慮していることと思います。
今回紹介するプロジェクトごとの構成の違いやメリット・デメリットが、Terraform運用の一助になれば幸いです。

Terraformとは

Terraformとはサーバ作成などをコードとして構成管理するインフラストラクチャツールです。
HCL言語で記述し、サーバの作成やコマンド実行など多岐にわたって利用することができます。

構成について

プロジェクトA

はじめてTerraformを使用したプロジェクト。
サーバやFWなど必要最小限の構成管理に使用しました。
ワールド制、単一リージョンで環境毎にディレクトリを分けた構成になりました。

以下がディレクトリ構成になります。

├── README.md
├── dev
├── manage
├── prd
├── prd-gke
├── stg
└── stg-gke

dev: 開発環境用
manage: 管理サーバやFW等の設定
prd: 本番環境のGCEやその他
prd-gke: 本番環境のGKE
stg: ステージング環境のGCEやその他
stg-gke: ステージング環境のGKE

GKEとGCEでディレクトリを分けてシンプルな構成になりました。ワールドはworkspaceで管理しています。
ワールド作成と統合を繰り返す必要があるプロジェクトのため、環境の作成・削除の回数が多く、作成はJenkinsで実行してました。

メリット

  • 同環境でもサービス毎に分けてstateを細かくすることで影響範囲を絞れる
  • ワールドをworkspaceで管理しているので、同じ構成を簡単に構築できる

デメリット

  • GCE側とGKE側でstateを利用したい場合のリソースが複雑化する

プロジェクトB

ワールド制、多リージョンで展開しているため、リージョン毎に構築しました。
また、ワールド制ということもあり、環境、ワールド、リージョンを管理するかなり大規模なものになってしまいました。

以下がディレクトリ構成になります。

├── README.md
├── dns
├── RegionA
│   ├── common
│   ├── dev_global_set
│   ├── dev_world_set
│   ├── prd_global_set
│   ├── prd_world_set
│   ├── stg_global_set
│   └── stg_world_set
└── RegionB
    ├── common
    ├── dev_global_set
    ├── dev_world_set
    ├── prd_global_set
    ├── prd_world_set
    ├── stg_global_set
    └── stg_world_set

dns: プロジェクト全体のDNS管理用
common: 管理サーバや環境全体で使用する物
dev_global_set: 開発環境の全ワールドで使う物
dev_world_set: 開発環境のワールドで使う物
prd_world_set: 本番環境の全ワールドで使う物
prd_world_set: 本番環境のワールドで使う物
stg_world_set: ステージング環境の全ワールドで使う物
stg_world_set: ステージング環境のワールドで使う物

各環境毎のディレクトリ内に必要なHCLが内包されています。ワールドはworkspaceで管理しています。

メリット

  • 環境毎にディレクトリが別れているため、他の環境に影響が起きないようになっている
  • ワールドをworkspaceで管理しているので、同じ構成を簡単に構築できる
  • リージョンによるサーバ構成の差異を条件分岐で記述していないので、運用時における可読性が容易

デメリット

  • リージョン毎に作成しているため、Terraformのファイル構成が冗長になって管理が面倒

ディレクトリ構成のデメリットではありませんが、ワールド毎に台数が変動する際、各ワールドが同じ変数を使ってしまっている事や、
同じ用途のディスクを複数台作成するのにcountを使用してしまったため、障害発生時にtfstateの更新が難しくなるなどの問題がありました。

プロジェクトC

stateファイルの分け方を意識して構成したTerraformになりました。
単一ワールド・単一リージョンのため、環境をworkspaceで分けた構成になっています。

以下がディレクトリ構成になります。

├── README.md
├── common
├── develop
├── devops
├── immutable
├── init
├── loadtest
└── mutable
    ├── analytics
    ├── cloudarmor
    ├── firewall
    ├── gce
    ├── gke-cluster
    ├── gke-node
    └── logging-sink

common: IAMやGCPプロジェクト全体に関わる物
develop: 開発環境で使用する物
devops: CIを利用する物
immutable: 環境毎に存在するが、運用中に変更しない物
init: Terraform用のバケットを作成したりTerraform実行用のサービスアカウント作成など
loadtest: 負荷試験に使用する物
mutable: 環境毎に存在し、運用中に変更する事がある物

特別な構成の環境を除いてworkspaceで管理しているため、環境毎のディレクトリが無い構成になっています。

メリット

  • ディレクトリを細分化することで、一つのstateで管理する範囲を小さくできた
  • 環境構成が近いため環境をworkspaceで区切って冗長なリソースを少なくできた
  • mutable内を細かく分けたので、運用時における更新や修正がしやすい

デメリット

  • workspaceの区切りが環境ごとなので差異が生じると条件分岐が多くなり可読性が悪くなる
  • 環境をworkspaceで切っているので、同じものを呼んでしまう可能性や影響を与える可能性がある

大量にリソースを記述する際はmoduleを使用するのも手ですが、可読性が悪くなるため使用しませんでした。

今後のTerraform運用について

これから改善していきたい内容や理想を考えてみました。

  • CIを使用してplanのチェック
  • githubのmasterにmergeされた時点でapplyが実行される(条件は色々必要そう)
  • moduleを使用したリソースの簡素化
  • 障害発生時におけるtfstateの管理のルール化

まだまだTerraformを使い始めたところなので、改善点は山程あります。
ディレクトリ構成に関してもベストプラクティスな状態を模索しています。

最後に

今回はディレクトリ構成について主に紹介しましたが、
Terraformを使用することで構築にかかる時間が減り、複数環境を作成する場合は大いに役立ちました。
構成管理という点でも、変更点をコードで可視化することができるので、いろんな人に見てもらうことが可能になりました。

Terraformにおけるディレクトリ構成は、事故防止と可読性、stateをなるべく細かく管理するために、環境ごとにディレクトリを分けることが大切です。
ただし、リージョンやワールド制など、プロジェクトには様々な条件が発生するため、適切に構成を変化させる必要があります。
少なくとも、

  • 本番はそれ以外の環境を混ぜない
  • 使用するサービス毎にディレクトリを分ける

ことで、1つのstateで管理するものが減り、運用の負担を減らせるのではないかと思います。