🕌

TerraformでCI/CDを構築する際、どこまでモジュール化すべき?

に公開

はじめに

AWSでCI/CD環境を構築する際、Terraformを使うと「IAMロール、S3、CodeBuild、CodePipeline...」と、リソースが芋づる式に増えていきます。

ここで直面するのが、「これ、どこまでひとまとめ(モジュール化)にするのが正解?」という問題です。今回は、私が実際に試行錯誤して辿り着いた「1パイプライン=1モジュール」という構成について紹介します。

結論から言うと、私は 「CodePipelineとその実行に必要なIAMロール・CodeBuildプロジェクトをまるごと1つのモジュールに閉じ込める」 という構成に落ち着きました。

なぜバラバラにしないのか?
最初は「IAMロールはIAMモジュールに」などと、リソースの種類ごとに分けようとしました。しかし、CodePipelineには以下の特徴があります。

密結合なIAMポリシー:
CodePipelineやCodeBuildのポリシーは、特定のS3バケットやCodeBuildプロジェクトに強く依存します。これらを別モジュールに分けると、モジュール間の値の受け渡し(OutputsとVariables)が複雑になりすぎてしまいます。

セットで管理したい:
「パイプラインをもう一つ増やしたい」となったとき、必要なリソースが1つのモジュールにまとまっていれば、module ブロックを1つ追加するだけで完結します。

実装例:main.tf の中身
今回作成した構成では、modules/codepipeline/ の中に、以下のリソースをすべて詰め込んでいます。

  • CodePipeline本体
  • CodeBuildプロジェクト
  • 各種実行用IAMロール & ポリシー

このようにモジュール内で完結させることで、呼び出し側は、バケット名やプロジェクト名などの最小限の変数(Variables)を渡すだけで良くなります。

ディレクトリ構成

modules/
  └── codepipeline/
      ├── main.tf      <-- CodePipeline, CodeBuild, IAMを記述
      ├── variables.tf <-- パイプライン名やリポジトリ名などを定義
      └── outputs.tf

呼び出し側

この構成にすると、利用側はこれだけで済みます。非常に宣言的で分かりやすくなります。

module "frontend_pipeline" {
  source       = "./modules/codepipeline"
  project_name = "my-frontend"
  artifact_s3_bucket = aws_s3_bucket.artifact.id
}

メリットとデメリット

この構成にしてみて感じたメリット・デメリットです。

項目 メリット デメリット
可読性 パイプラインに関わる設定が1箇所に集約される IAM定義を含めると、1ファイルの行数が多くなりがち
再利用性 他のプロジェクトや環境(stg/prod)への展開が容易 「このIAMロールだけ全パイプラインで共通化したい」という柔軟な変更には不向き

まとめ

「どこまでモジュール化するか」の答えに正解はありませんが、「運用時にどこをセットで変更するか?」を考えると、自ずと境界線が見えてきます。
CI/CDの場合は、パイプラインの構成(ビルド手順や権限)が変わることが多いため、1つのモジュールにまとめて「独立してデプロイ・管理できる状態」にするのが、運用負荷を下げる近道だと感じました。

Discussion