GHCRでCI/CDの中途半端なプロジェクトを再構成してみた

個人開発で使っているNext.js + Express + React Viteの構成、デプロイまわりがかなり場当たり的になっていたので、GHCRを軸にCI/CDを整理し直すことにした。進捗あれば随時追記していく。

目次

これまでの構成

ローカル環境

Next.jsはnpm run devで直接起動、React Viteも同様に直接起動している。BackendとMySQLだけdocker-composeで動かしていた。つまりローカルではDockerに寄せきれておらず、フロント系は素で動かしている状態。

Lightsail(本番)

/var/www/app/にリポジトリをクローンし、docker-compose.prod.ymlでbackend・Next.js・MySQLをDockerコンテナとして動かしている。React Vite(管理画面)はビルド済みの静的ファイルを/var/www/app/backend/public/に配置し、ホスト側のNginxから配信。Nginxはリバースプロキシとして各サービスの前段に立っている。

何が問題だったか As-Is → To-Be

Next.jsの二重ビルド問題

GitHub Actionsでビルド → scpでファイル転送 → Lightsail上でさらにDocker再ビルド、という流れになっていた。せっかくCIでビルドしているのに、本番側でもう一度ビルドが走る無駄な構成。

またLightsail上でビルドするフローのため、AWSコンソール画面でメトリクスでバーストキャパシティの枯渇を確認しました、、Next.jsのビルド中にメモリ不足で502エラーが発生しており、デプロイが不安定な状態です。

Backend:Lightsailでビルドが走る

Lightsail上でgit pullしてからdocker buildしている。ビルドがサーバー上で走るので、CI/CDとしては中途半端。サーバーのリソースも食うし、ビルドの再現性も担保しにくい。

React Vite:同じくサーバー上でビルド

Lightsail上でgit pullnpm run build。これも本番サーバーでビルドしているので同じ問題。

共通しているのは「ビルドをどこでやるか」が統一されていないこと。GitHub Actionsがあるのに活かしきれていなかった。

3つのリポジトリは別々?それとも1つのモノレポ?

As-Is

親リポジトリはnext-basic/, vite-react-0206/, backend/をgitignoreしていて、それぞれが独立したリポジトリ。

親リポジトリにはdocker-compose.yml, initdb/, db/.envなどの共通設定だけがある。

To-Be 推奨する構成変更

親リポジトリ(express-mysql-docker)は不要にできる。各リポジトリが自分のDockerイメージをGHCRにpushし、Lightsail側にはdocker-compose.prod.ymlとNginx設定だけ置く。

[GitHub]
  backend repo      → ghcr.io/あなた/backend:latest
  next-basic repo   → ghcr.io/あなた/nextjs:latest
  vite-react repo   → ghcr.io/あなた/admin:latest (nginx+静的ファイル)

[Lightsail]
  /var/www/app/
    docker-compose.prod.yml   ← これだけ管理
    initdb/                   ← 初期化SQL(既存のまま)
    db/.env                   ← MySQL認証情報
    backend/.env              ← Backend認証情報
  
  Nginx (ホスト側) → 今とほぼ同じ
  
  docker compose pull && docker compose up -d  ← デプロイはこれだけ

GHCRを使った新しい構成

方針はシンプルで、GitHub Actionsでイメージをビルドしてghcr.ioにpush → Lightsailではpullしてdocker compose up -dするだけにする。

GitHub Actions(ビルド & push)
  → ghcr.io/<user>/backend:latest
  → ghcr.io/<user>/nextjs:latest
  → ghcr.io/<user>/admin:latest(nginx + 静的ファイル)

Lightsail(pull & run)
  docker compose -f docker-compose.prod.yml up -d
  + Nginx(ホスト側、既存のまま)

これでLightsail上ではビルドが一切走らなくなる。デプロイはdocker compose pull && docker compose up -dだけ。

進める前に確認・決めたいこと

React Vite管理画面のコンテナ化

今はビルド済みファイルをホスト側Nginxから直接配信しているが、nginx + 静的ファイルのDockerコンテナにするのが自然だと思う。コンテナにすれば他と同じくGHCRからpullするだけで済む。

リポジトリ構成

express-mysql-dockerの中に全部入っているモノレポっぽい構成に見えるが、React ViteとNext.jsのGitHub Actionsが別リポジトリのようにも見える。ここの整理が必要。

MySQLのデータ移行

既存のdocker volumeをそのまま使えば問題ないはず。コンテナを差し替えてもvolumeは維持される。

今後の予定

構成が固まり次第、GitHub Actionsのワークフロー作成から着手する。進捗があれば追記予定。


最終更新:2025年2月

目次