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_dump
やpgBackRest
の活用もおすすめです。
- セキュリティ:パブリックリポジトリで実行するとサプライチェーン攻撃の標的になりやすい。ジョブごとに 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 で小さく始め、テストが遅く感じたら並列化や自己ホストに進む──このステップアップ型が現場では失敗しにくい王道パターンです。今日のプルリクからぜひ導入してみてください。