Spring Boot(Gradle)× ECSのバックエンドで、CIをGitHub Actions、CDをAWS CodePipelineという別基盤で構成しています。同じCI/CDパイプラインの中に統合することも技術的には可能ですが、あえて分離する場合にどう責務を割り振るかを整理します。
全体像
PR作成・push
→ GitHub Actions (CI)
フォーマットチェック → テスト → Dockerビルド確認
mainへのマージ
→ AWS CodePipeline (CD)
Source → Build(イメージビルド + DBマイグレーション) → Deploy(ECS更新)
CIはマージ前のゲート、CDはマージ後の自動デプロイという時間軸で役割が分かれています。
CIが担保すること
GitHub Actionsのジョブは、PRの段階で「コードとして正しいか」を検証します。
- name: Check code format
run: ./gradlew spotlessCheck
- name: Run tests
run: ./gradlew test
- name: Build Docker image
run: docker build -t ec-api-backend:ci .
- フォーマット:レビューでスタイルの指摘をしないために、機械的に弾く
- テスト:ロジックの破壊的変更を検知する
-
Dockerビルド確認:Dockerfileの記述ミスや
COPYパスの誤りなど、コンテナ化できない状態のコードをマージさせない
ここでの共通点は、すべてローカルの情報だけで完結する検証という点です。外部のAWSリソースやDBには一切触れません。
CDが担保すること
AWS CodePipelineは、mainマージ後に「実際の環境にデプロイできる状態か」を検証しながらデプロイまで進めます。
# buildspec.yml の一部
- docker build -t $IMAGE_URI backend
- aws ecs run-task --cluster $ECS_CLUSTER --task-definition $FLYWAY_TASK_DEF_FAMILY ...
# Flywayタスクの完了をポーリングし、失敗ならビルドを止める
- イメージビルド:本番相当の環境でのビルド(ECR push込み)
- DBマイグレーション:実際のDBに対してFlywayを実行し、失敗すればパイプラインを止める
- デプロイ:ECSサービスのタスク定義を更新
CIと違い、こちらは実際のAWSリソース(ECS、RDS/Auroraなど)に触れる検証です。ローカルでは再現しづらい、環境固有の失敗(IAM権限不足、ネットワーク設定ミス、実データに対するマイグレーション失敗)をここで検知します。
重複しているように見えて重複していない箇所
CIの「Dockerビルド確認」と、CDのBuildステージの「イメージビルド」は、どちらもdocker buildを実行している点で似ています。ここは意図的な二重チェックです。
- CIでのビルド:PRの時点で「Dockerfileが壊れていないか」を早期に検知する。マージ前に落とせるものはここで落とす
- CDでのビルド:実際にECRへpushする本番用のビルド。CIでのビルドとは別のタイミング・別の環境(CodeBuild)で再度実行される
CIを通過したからといってCDのビルドを省略しない設計にしているのは、CIとCDが完全に別基盤である以上、片方の結果をもう片方が信頼する仕組み(アーティファクトの受け渡しなど)を作っていないためです。二重に見えるコストと引き換えに、CIとCD が互いに疎結合であることを優先しています。
境界線をどこに引くか
CIとCDの境界を「mainマージ」に置いている設計は、以下の判断に基づいています。
- PRの段階でAWSリソースに触れる検証(DBマイグレーションなど)をやろうとすると、PRごとに使い捨てのAWS環境が必要になり、コストと複雑さが増す
- 「ローカルで再現できる検証はCI」「実環境が絡む検証はCD」と割り切ることで、CIは高速に、CDは確実性重視に、という別々の最適化ができる
逆に言うと、CIを通過したPRが必ずしも本番で問題なく動くとは限りません。CDのBuildステージでマイグレーション失敗を検知してパイプラインを止める仕組みは、この「CIでは検知できない領域が残っている」ことを前提にした安全弁です。
まとめ
| CI(GitHub Actions) | CD(AWS CodePipeline) | |
|---|---|---|
| トリガー | PR作成・push | mainへのマージ |
| 検証対象 | コード単体(ローカル完結) | 実環境込み(AWSリソース) |
| 代表的なチェック | フォーマット、テスト、Dockerビルド確認 | イメージビルド、DBマイグレーション、デプロイ |
| 失敗時の影響範囲 | マージがブロックされる | パイプラインが止まる(本番には反映されない) |
CIとCDを別基盤にする場合、「何を検証できてCIで完結するか」「何がCDでしか検証できないか」を切り分けておくと、重複や抜け漏れに気づきやすくなります。