GitHub ActionsでPostgreSQLを使ったCI構築ガイド|動くDB付きテスト環境を最短で整える方法

GitHub ActionsでPostgreSQLを使ったCI構築ガイド|動くDB付きテスト環境を最短で整える方法

GitHub ActionsでPostgreSQLを使ったCI構築ガイド|動くDB付きテスト環境を最短で整える方法

GitHub ActionsでPostgreSQLを組み込めば、本番さながらのデータベース付きCIが手軽に実現できます。この記事では、YAMLの最小構成からSelf-hosted Runner運用まで、現場で役立つベストプラクティスを解説します。

目次

GitHub Actions×PostgreSQLをCIに組み込む理由:DBが動く“本番同等”テスト環境でバグを未然に防ぐ

「ユニットテストは通るのに、本番投入したら N+1 クエリで500エラー……」──そんな悲劇を回避する最短ルートは、CI で本物の Postgres を立ち上げて結合テストまで自動化することです。

GitHub Actions には service container という仕組みがあり、わずか十数行の YAML で Postgres をジョブごとに自動起動できます。

ジョブ終了後はコンテナごと破棄されるため、ローカル環境を汚さずクリーンアップも不要。さらにGitHub Free 2,000 分/GitHub Pro 3,000 分までは追加コストなしで使えるので、個人開発ならまず無料の範囲で収まります。

PostgreSQL を CI に組み込むメリット

  • 本番と同一バージョンで検証postgres:16.3-alpine などタグをピン止めすればバージョン不一致の事故を防げます。
  • マイグレーション忘れを撲滅:ワークフロー内で自動実行し、スキーマ差分の取りこぼしを検知。
  • 並列ジョブごとに独立した DB:PR どうしのデータ衝突を回避し、レビューフローがスムーズ。
  • ローカル依存ゼロ:新人が Postgres をインストールせずに開発参加でき、オンボーディングが高速化。

service container/VM 直起動/Self-hosted Runner 比較

方式起動速度設定量データ保持向くケース
service container◎(10〜15 秒)少ないジョブ終了で削除ユニット〜統合テスト
VM 直起動○(30 秒前後)やや多いジョブ終了で削除Docker NG 環境
Self-hosted Runner◎(常駐)ランナー側で管理永続可重量級 E2E/複数 DB

Self-hosted Runner は高速ですが、OS更新やパッケージ衝突を自前で管理する必要があります。社内ネットに直接接続する場合はファイアウォールや IAM 制御も忘れずに。

まずは動かす:改良版ミニマル YAML

.github/workflows/ci-postgres.yml を下記のように用意しましょう。

name: CI with Postgres
on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

```
services:
  postgres:
    image: postgres:16-alpine
    env:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp_test
    ports:
      # ホスト側ポートは <strong>あえて指定しない</strong>ことで
      # GitHub が自動で空きポートを割り当てる
      - 5432
    options: >-
      --health-cmd pg_isready
      --health-interval 10s
      --health-timeout 5s
      --health-retries 5

env:
  DB_HOST: 127.0.0.1
  # 自動割り当てされたポート番号を取得
  DB_PORT: ${{ job.services.postgres.ports['5432'] }}
  DB_USER: postgres
  DB_PASSWORD: postgres
  DB_NAME: myapp_test

steps:
  - uses: actions/checkout@v4

  - name: Set up Node
    uses: actions/setup-node@v4
    with:
      node-version: '20'

  - name: Install deps, migrate & test
    run: |
      npm ci
      npm run migrate   # ここで DB が出来ている想定
      npm test
```

上記のポイントは 127.0.0.1 と動的ポート: localhost だと IPv6 → IPv4 解決順序の違いで稀に接続失敗するケースが報告されているため、明示的に 127.0.0.1 を指定しています。

自動割り当てポートは ${{ job.services.postgres.ports['5432'] }} の形で取り出せるので固定 5432 を前提にしない運用が安全です。

Docker を使わず VM 直起動するパターン

Docker に制限がある環境では、APT で Postgres を入れる方法もあります。ただし systemctl 起動・停止の手順やバージョン固定を自前スクリプトで管理する必要があり、メンテナンスコストは高めです。CI のボトルネック分析後に “どうしても必要” となるまでは service container がおすすめです。

CI を高速化するベストプラクティス

Postgres コンテナ自体は軽量でも、マイグレーションやフィクスチャ投入で1〜2分かかることがあります。

  • 初期化不要データは Volume に載せない:毎回ロードする CSV がある場合は S3 など外部ストレージ経由に。
  • ログレベルを抑えるPOSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C" で initdb を高速化。
  • テストのシャーディングmatrix 戦略+jest --runInBand=false 等で並列化し、GitHub 5 同時ジョブ上限をフルに活用。
  • 無料分の把握:GitHub Free は 2,000 分/月、Pro は 3,000 分/月を超えると従量課金へ。パブリックリポジトリは Linux ランナー無制限ですが macOS や Windows は課金対象なので注意です。

よくあるエラーと安全なリセット方法

  • ECONNREFUSED
  • コンテナが起動前か、ポート競合が疑われます。pg_isready のヘルスチェック回数を 10→20 に増やすと解消する例も。
  • パスワード認証失敗
  • .env と CI 環境変数のダブル管理ミスが典型。Secrets Manager とリポジトリ直書きが混在していないか確認しましょう。
  • データ残骸が残る
  • スキーマ丸ごと消す場合は DROP SCHEMA public CASCADE; CREATE SCHEMA public; が便利ですが、アプリ側マイグレーションツールが Public スキーマ外を参照する場合は壊れる恐れがあります。事前にロールバックテストし、必要なら pg_restore --clean や DB Cleaner ライブラリを使う方が安全です。

Self-hosted Runner を選ぶときの注意点

自己ホストランナーはキャッシュ済みコンテナや常駐 DB で超高速ですが、メリットとトレードオフがはっきりしています。

PostgreSQL を永続化する場合のポイントとしては、コンテナ内のデータディレクトリをホスト側にマウントするのが基本です。

例:

docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=postgres \
  -v /srv/postgres/data:/var/lib/postgresql/data \
  postgres:16

このように-vオプションでホストに保存すれば、Postgres のバージョンアップや再起動後もデータが保持されます。バックアップにはpg_dumppgBackRestの活用もおすすめです。

  • セキュリティ:パブリックリポジトリで実行するとサプライチェーン攻撃の標的になりやすい。ジョブごとに Docker in Docker で隔離するか、プライベートネットワークに閉じること。
  • リソース競合:複数リポジトリが同じ Runner を共有し、CPU/I/O が飽和するとテストが不安定化。Prometheus + Grafana 監視は必須です。
  • 運用コスト:OS アップデート、Postgres バージョン更新、SELinux/AppArmor 設定など “インフラ運用業” が増える点に注意しましょう。

まとめ:Postgres 付き GitHub Actions で“データベースごと安心”な CI を

数行の YAML を追加するだけで、データベース由来のバグを PR 時点で潰せる開発体験が手に入ります。動的ポートを使えばホスト OS や GitHub API の将来変更にも強く、Self-hosted Runner を選ぶ際はセキュリティと運用負荷を秤にかければ OK。

まずは service container で小さく始め、テストが遅く感じたら並列化や自己ホストに進む──このステップアップ型が現場では失敗しにくい王道パターンです。今日のプルリクからぜひ導入してみてください。

Pantherでスクリーンショット&デバッグ自動化|PHP製E2Eテスト環境を完全ガイド

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次