Contents
はじめに
このガイドは、Docker 化した Django アプリケーションを 安全かつ自動化されたフローで本番環境へデプロイ するための実践的手順をまとめたものです。
ローカル開発から CI/CD パイプライン構築、運用監視までを一貫して扱うことで、セットアップにかかる時間とミスを大幅に削減できます。
以下では、前提条件・Dockerfile のベストプラクティス・docker‑compose 設定・CI/CD 実装・運用上の注意点を順に解説します。
前提条件と環境準備
本セクションでは、本ガイド全体で必要となるツールやバージョン、そして快適に開発・テストできるハードウェア要件について説明します。
正しいバージョンを揃えておくことで、予期せぬ依存関係エラーやパフォーマンス低下を防げます。
必要なツールとインストール手順
| ツール | 推奨バージョン | インストール方法の概要 |
|---|---|---|
| Python | 3.12(pyenv 推奨) |
curl https://pyenv.run \| bash → pyenv install 3.12.0 → pyenv global 3.12.0 |
| Docker Engine | 最新版 | https://docs.docker.com/engine/install/ の公式手順に従う(Linux は apt-get、macOS は Docker Desktop) |
| Docker Compose | v2 系プラグイン形式 | docker compose version で確認。v2.x が表示されれば OK |
| Git | 2.45+ | パッケージマネージャまたは公式サイトから取得 |
| make | 任意(ビルド自動化用) | 多くの Linux ディストリビューションに同梱 |
ポイント:Python と Docker のバージョンが揃っていれば、ローカル環境と CI 環境で挙動が一致しやすくなります。
推奨ハードウェアリソース
開発・テスト時に快適に作業できる最低要件と、実際の負荷を想定した推奨設定を表にまとめました。
※本表は Docker Desktop のデフォルトメモリ上限やマルチステージビルドのキャッシュ利用を考慮しています。
| 項目 | 最低要件 | 推奨設定 |
|---|---|---|
| CPU | 2 コア | 4 コア以上 |
| メモリ | 4 GB | 8 GB 以上(Docker Desktop のメモリ上限を超えないように) |
| ストレージ | SSD 推奨 | 空き領域 20 GB 以上 |
機密情報の取り扱いと .env ファイルの注意点
開発時に環境変数を手軽に管理できる .env は便利ですが、誤ってリポジトリへコミットするとシークレットが漏洩する危険があります。
以下の対策を必ず実施してください。
.gitignoreに追加 –*.envを必ず除外し、リモートにプッシュされないようにします。.env.exampleの活用 – 本番で使用するキーは空欄またはプレースホルダーにして配布し、実際の値はローカルだけで保持します。- アクセス権限の最小化 – 開発マシン上でもファイルパーミッションを
600(所有者のみ読み書き)に設定します。
開発チームへの共有方法:Slack のプライベートチャネルや社内秘密管理ツールでキーを配布し、
.envは各自がローカルで作成するフローを推奨します。
Dockerfile のベストプラクティス
この章では、イメージサイズ削減・ビルド高速化・ランタイムのセキュリティ向上を実現する マルチステージ構築 と レイヤ最適化、さらに 非 root 実行 の具体的手順を示します。
マルチステージビルド例
以下は、依存関係のインストールとアプリケーションコードだけをランタイムイメージへコピーする典型的な構成です。
builder ステージでキャッシュを活用し、最終イメージに不要なツールチェーンが残らないようにしています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# ---- Build stage ------------------------------------------------- FROM python:3.12-slim AS builder ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 WORKDIR /app # 依存関係だけを先にインストールし、キャッシュを有効化 COPY requirements.txt . RUN pip install --upgrade pip && \ pip install -r requirements.txt --target=/install # ---- Runtime stage ----------------------------------------------- FROM python:3.12-slim ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 WORKDIR /app # builder で作成した依存関係をコピー COPY --from=builder /install /usr/local/lib/python3.12/site-packages COPY . . # 非 root ユーザー作成と権限付与 RUN groupadd -r django && \ useradd -r -g django django && \ mkdir -p /app/static /app/media && \ chown -R django:django /app USER django EXPOSE 8000 ENTRYPOINT ["/app/entrypoint.sh"] CMD ["gunicorn", "myproject.wsgi:application"] |
重要ポイントの解説
| 項目 | 説明 |
|---|---|
--target=/install |
依存関係だけを別ディレクトリにインストールし、ランタイムイメージへコピーすることでビルドツールが残らない |
chown -R django:django /app |
ボリュームマウント先や static/media ディレクトリの書き込み権限を事前に付与しておくと、コンテナ起動後のエラーを防げる |
USER django |
root 権限で実行するリスクを排除し、最小権限の原則(Principle of Least Privilege)を遵守 |
レイヤキャッシュ活用と不要ファイル削除
- 依存関係は分割 – 変更頻度が低い
requirements-base.txtとアプリ固有のrequirements.txtに分け、COPY requirements-base.txt . && pip install -r requirements-base.txtを先に実行すると、ソースコード変更時でもキャッシュが効き続けます。 - APT キャッシュのクリア –
apt-get update && apt-get install -y <pkg> && rm -rf /var/lib/apt/lists/*のように、インストール直後にリポジトリ情報を削除してイメージサイズを最小化します。 - ビルドコンテキストの肥大化防止 –
.dockerignoreを正しく設定し、不要なファイルが送られないようにします(次節参照)。
.dockerignore の推奨例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# Python 関連 __pycache__ *.py[cod] *.pyo *.pyd venv/ env/ # Git 管理外の機密情報 .env .secret* *.pem # OS/IDE が生成するファイル .DS_Store Thumbs.db .vscode/ .idea/ # ビルド成果物 staticfiles/ media/ build/ dist/ |
効果:
.dockerignoreにより Docker デーモンへ送信されるコンテキストが数十 MB から数百 KB に削減され、ビルド時間とネットワーク帯域の無駄遣いを防げます。
docker‑compose によるサービス定義
このセクションでは、ローカル開発・ステージング・本番で共通に利用できる docker‑compose.yml の構成要素と、機密情報管理のベストプラクティスを紹介します。
web, nginx, db, redis の四つのサービスを例示し、環境ごとのオーバーライド方法も併せて解説します。
基本構成(docker‑compose.yml)
以下のファイルは 開発 と 本番 で同一に利用できるベースです。
env_file により .env の内容が自動的に注入され、機密情報は Docker secret へ切り替えるだけで安全に扱えます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
version: "3.9" services: web: build: . env_file: - .env # 開発時はローカル .env を使用 environment: - GUNICORN_WORKERS=${GUNICORN_WORKERS} depends_on: - db expose: - "8000" networks: - backend nginx: image: nginx:1.27-alpine ports: - "80:80" - "443:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro - static_volume:/app/static - media_volume:/app/media depends_on: - web networks: - backend db: image: postgres:16-alpine environment: POSTGRES_USER_FILE: /run/secrets/db_user POSTGRES_PASSWORD_FILE: /run/secrets/db_password POSTGRES_DB: ${POSTGRES_DB} volumes: - pg_data:/var/lib/postgresql/data secrets: - db_user - db_password networks: - backend redis: image: redis:7-alpine ports: ["6379:6379"] networks: - backend networks: backend: volumes: pg_data: static_volume: media_volume: |
説明ポイント
env_fileは開発時に便利ですが、本番ではsecrets:と組み合わせて使用することで、.envが漏洩しても機密情報は保護されます。exposeは内部ポートだけを宣言し、外部からの直接アクセスは Nginx のみ許可します。
開発向けオーバーライド(docker‑compose.override.yml)
開発時にコード変更を即座に反映させるためのボリュームマウントと、runserver への切り替え例です。
|
1 2 3 4 5 6 |
services: web: volumes: - .:/app:cached # ソースコードをリアルタイムで共有 command: python manage.py runserver 0.0.0.0:8000 |
注意:
docker-compose.override.ymlは自動的にdocker compose upに組み込まれますが、CI 環境では明示的に除外してください。
.env と Docker secret の併用例
|
1 2 3 4 5 |
# .env.example(プロジェクトルートに配置し配布) POSTGRES_USER=postgres_user POSTGRES_DB=myproject GUNICORN_WORKERS=4 |
本番環境では次のように secret を作成します。
|
1 2 3 4 |
echo "super-secret-key" | docker secret create django_secret_key - echo "dbuser123" | docker secret create db_user - echo "strongpwd!" | docker secret create db_password - |
docker‑compose.yml の secrets: に登録したら、コンテナ内部では /run/secrets/<name> から値を取得できます。
エントリポイントスクリプトと起動フロー
Docker コンテナが起動するたびに行うべき初期化処理は entrypoint.sh にまとめます。
以下のサンプルでは、シークレット読み込み・DB 接続待機・マイグレーション・static 収集を順序立てて実行しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#!/bin/bash set -euo pipefail # ---------- シークレット取得 ---------- if [ -f /run/secrets/django_secret_key ]; then export DJANGO_SECRET_KEY=$(cat /run/secrets/django_secret_key) fi # ---------- DB 接続待機 ---------- until python manage.py migrate --check >/dev/null 2>&1; do echo "Waiting for PostgreSQL..." sleep 3 done # ---------- マイグレーションと static 収集 ---------- python manage.py migrate --noinput python manage.py collectstatic --noinput # ---------- アプリ起動 ---------- exec "$@" |
set -euo pipefailによりエラー時に即座にスクリプトが停止し、コンテナの不正状態での稼働を防ぎます。exec "$@"で Dockerfile のCMD(Gunicorn)へ制御を渡すため、シグナル転送が正しく機能します。
Dockerfile への組み込み例
|
1 2 3 4 5 |
COPY entrypoint.sh /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh ENTRYPOINT ["/app/entrypoint.sh"] CMD ["gunicorn", "myproject.wsgi:application"] |
CI/CD パイプライン構築(GitHub Actions + Docker Buildx)
本章では、マルチプラットフォーム対応イメージを自動でビルド・テスト・レジストリへ push し、Swarm スタックへデプロイするまでのフローを解説します。
CI が失敗した場合は即座にロールバックできるようタグベースの戦略も併せて示します。
ワークフロー全体像
- コードチェックアウト → 変更があればビルドトリガーへ進む
- QEMU と Buildx のセットアップ(マルチアーキテクチャ対応)
- レジストリ認証(GHCR または ECR)
- イメージビルド & プッシュ(
docker buildx build --platform ... --push) - Swarm へデプロイ(SSH 経由で
docker stack deploy実行)
GitHub Actions ワークフロー例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
name: CI/CD for Django Docker App on: push: branches: [ main ] jobs: build-and-deploy: runs-on: ubuntu-latest permissions: contents: read packages: write id-token: write # ECR 用 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up QEMU (multi‑arch) uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Log in to GitHub Container Registry if: ${{ secrets.GHCR_TOKEN != '' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GHCR_TOKEN }} - name: Log in to Amazon ECR (optional) if: ${{ secrets.AWS_ROLE_ARN != '' }} uses: aws-actions/amazon-ecr-login@v2 - name: Determine image tag id: vars run: | TAG=$(git rev-parse --short HEAD) echo "TAG=$TAG" >> $GITHUB_ENV - name: Build and push Docker image run: | IMAGE=ghcr.io/${{ github.repository }}:${{ env.TAG }} docker buildx build \ --platform linux/amd64,linux/arm64 \ -t $IMAGE \ --push . - name: Deploy to Swarm (SSH) uses: appleboy/ssh-action@v0.1.9 with: host: ${{ secrets.SWARM_HOST }} username: ${{ secrets.SWARM_USER }} key: ${{ secrets.SWARM_SSH_KEY }} script: | docker stack deploy -c stack.yml prod \ --with-registry-auth \ --resolve-image changed |
重要な設定ポイント
--with-registry-authはプライベートレジストリの認証情報を自動で渡すため必須です。--resolve-image changedにより、イメージが更新されたときだけサービスが再起動します。
ロールバック戦略(タグベース)
- デプロイ時に Git コミット SHA をタグ付けし、同じタグをイメージ名に使用。
- 障害発生時は
docker service update --image ghcr.io/yourorg/django-app:<前のSHA> prod_webで即座にロールバック。
ブルー/グリーンデプロイの実装例(Swarm)
| 手順 | 内容 |
|---|---|
| 1 | stack-blue.yml と stack-green.yml を別々に用意し、サービス名にサフィックス (web_blue, web_green) を付与 |
| 2 | 外部ロードバランサ(例:AWS ALB)のターゲットグループを切り替えてトラフィックを移行 |
| 3 | 新スタックがヘルスチェック通過後、旧スタックを docker stack rm で削除 |
監視・ログ収集とトラブルシューティング
本章では、運用時に必須となる ログの集中管理 と メトリクス可視化 の手順、および頻出エラーへの対処法をまとめます。
ログの標準出力化と集約
- Gunicorn は
accesslog = '-'、errorlog = '-'と設定し、すべて Docker の stdout に流す。
python
# gunicorn.conf.py
accesslog = '-'
errorlog = '-' - Nginx はコンテナ内部で
/var/log/nginxを作成し、docker run -v $(pwd)/nginx_logs:/var/log/nginxでホストに永続化。 - ELK / Loki + Grafana:Docker の JSON ログ形式をそのまま収集エージェント(Filebeat or Promtail)へ流し、検索・可視化を実現。
メトリクス取得とダッシュボード構築
| コンポーネント | Exporter | エンドポイント |
|---|---|---|
| Django アプリ | django-prometheus |
/metrics/ |
| Nginx | nginx-prometheus-exporter |
http://nginx:9113/metrics |
| PostgreSQL | postgres_exporter |
localhost:9187 |
docker‑compose.yml に追加する例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
prometheus: image: prom/prometheus:latest volumes: - ./prometheus:/etc/prometheus ports: - "9090:9090" grafana: image: grafana/grafana-oss depends_on: - prometheus ports: - "3000:3000" |
- Prometheus の設定ファイル
prometheus.ymlに上記エクスポーターをジョブとして登録し、Grafana で公式テンプレート(Django, Nginx)をインポートすれば即時に可視化できます。
よくある障害と対処フロー
| 障害シナリオ | 主な原因 | 確認手順 | 推奨解決策 |
|---|---|---|---|
| コンテナ起動失敗 (exit code 1) | SECRET_KEY 未設定、ポート競合 |
docker logs <コンテナ> → エラーメッセージ確認 |
.env・Docker secret を再確認し、EXPOSE とホストポートの重複を解消 |
| static ファイル 404 | collectstatic が実行されていない、STATIC_ROOT パス違い |
コンテナ内で ls /app/static/ 確認 |
entrypoint.sh に必ず collectstatic --noinput を入れる |
| DB 接続エラー | 環境変数ミスマッチ、ネットワーク未接続 | docker exec -it <web> ping db |
.env の POSTGRES_* 系を統一し、networks: 設定が正しいか確認 |
| Gunicorn workers 過多で OOM | CPU コア数に対して過剰な workers を設定 | docker stats でメモリ使用率監視 |
workers = min((CPU*2)+1, 8) 程度に抑える |
記事のまとめ(約260文字)
本稿では、Python 3.12 と Docker の最新版を前提にした開発環境構築から、マルチステージ Dockerfile・非 root 実行・.dockerignore によるビルド最適化までのベストプラクティスを解説しました。
docker‑compose.yml では 機密情報は .env と Docker secret のハイブリッドで安全に管理し、エントリポイントでマイグレーション・static 収集を自動化します。
CI/CD は GitHub Actions + Buildx でマルチプラットフォームイメージを GHCR/ECR に push、Swarm の docker stack deploy で本番へデプロイし、タグベースのロールバックやブルー/グリーン構成も実装可能です。
運用フェーズでは Prometheus+Grafana と ELK/Loki によるログ・メトリクス集中管理と、典型的な障害への対処手順を提供することで、Docker 化 Django アプリの安全かつ高速な本番移行を実現します。