開発・技術選定

GitHub Actions で Django の CI/CD を組む — テストを通ったものだけ本番へ

手動デプロイは、慣れるほど確認が雑になります。
テストを通ったものだけが本番に出る仕組みにすると、
修正から反映までが数分になり、小さな改善を出しやすくなります。

ワークフローの構成

name: deploy
on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      db:
        image: postgres:14
        env: { POSTGRES_PASSWORD: test }
        options: >-
          --health-cmd pg_isready --health-interval 5s --health-retries 10
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.11", cache: pip }
      - run: pip install -r requirements.txt
      - run: ruff check .
      - run: python manage.py makemigrations --check --dry-run   # 反映漏れ検知
      - run: python manage.py test

  deploy:
    needs: test           # ← テストが通らなければ実行されない
    runs-on: ubuntu-latest
    steps:
      - uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.HOST }}
          key: ${{ secrets.SSH_KEY }}
          script: /srv/app/deploy.sh

needs: test が要点です。これでテスト失敗時にデプロイが止まります。

makemigrations --check を必ず入れる

モデルを変更したのにマイグレーションを作り忘れる、
という事故は必ず起きます。CI で機械的に検出します。

python manage.py makemigrations --check --dry-run
# 未作成の変更があれば非ゼロで終了する

サーバー側のデプロイスクリプト

#!/usr/bin/env bash
set -euo pipefail          # エラーで即停止(これが無いと途中失敗を見逃す)

cd /srv/app
git pull --ff-only

# マイグレーション前にダンプ(切り戻せるように)
pg_dump -Fc mydb > /var/backups/pre_deploy_$(date +%Y%m%d_%H%M%S).dump

venv/bin/pip install -q -r requirements.txt
venv/bin/python manage.py migrate --noinput
venv/bin/python manage.py collectstatic --noinput

systemctl reload myapp     # graceful(処理中のリクエストを落とさない)

set -euo pipefail が無いと、途中でコケても最後まで走り
「成功したように見えて壊れている」状態になります。

秘密情報の扱い

SSH 鍵やトークンは GitHub の Secrets に置き、リポジトリには入れません
デプロイ用の鍵は専用に作り、実行できる操作を最小限にします。

command="/srv/app/deploy.sh",no-port-forwarding ssh-ed25519 AAAA...

authorized_keyscommand= を付けると、その鍵では
デプロイスクリプト以外を実行できなくなります

自動デプロイをやってよい条件

  • テストがある(無いなら、自動化は事故を速くするだけ)
  • 切り戻せる(ダンプ、あるいは1つ前のコミットに戻せる)
  • 落ちたことに気づける(デプロイ後のヘルスチェック)

この3つが揃っていないうちは、手動のほうが安全です。

まとめ

  • needs: でテスト通過を必須にする
  • makemigrations --check でマイグレーション漏れを検出
  • デプロイスクリプトは set -euo pipefail から始める
  • マイグレーション前に必ずダンプ
  • SSH 鍵は command= で操作を限定する