はじめに
本記事では、DjangoアプリケーションをDocker Composeで本番環境にデプロイする構成について解説します。
ディレクトリ構成
今回のプロジェクト構成は以下の通りです。
project/
├── docker-compose.yml
├── containers/
│ └── django/
│ ├── Dockerfile
│ └── entrypoint.sh
├── nginx/
│ ├── Dockerfile
│ └── default.conf
├── app/
│ └── Django project
└── db/
それぞれの役割を順番に解説します。
docker-compose.yml
docker-compose.yml は、複数のコンテナをまとめて管理するためのファイルです。
今回の構成では、主に以下の3つのコンテナを定義します。
db : PostgreSQL
app : Djangoアプリケーション
nginx : リバースプロキシ
例は以下です。
version: "3.8"
services:
db:
image: postgres:15
container_name: webapp_db
environment:
POSTGRES_DB: mydb
POSTGRES_USER: myuser
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
- ./db/backup:/backup
networks:
- webapp_network
app:
container_name: webapp_app
build:
context: .
dockerfile: ./containers/django/Dockerfile
environment:
- DJANGO_SETTINGS_MODULE=project.settings
env_file:
- .env
volumes:
- ./app:/code
- static_volume:/code/staticfiles
- media_volume:/code/media
expose:
- "8000"
command: sh -c "/usr/local/bin/entrypoint.sh"
depends_on:
- db
networks:
- webapp_network
nginx:
container_name: webapp_nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- "80:80"
- "443:443"
volumes:
- static_volume:/staticfiles
- media_volume:/media
- /etc/letsencrypt:/etc/letsencrypt:ro
depends_on:
- app
networks:
- webapp_network
volumes:
db_data:
static_volume:
media_volume:
networks:
webapp_network:
driver: bridge
dbコンテナ
db:
image: postgres:15
db コンテナではPostgreSQLを使用します。
environment:
POSTGRES_DB: mydb
POSTGRES_USER: myuser
POSTGRES_PASSWORD: password
ここでは、データベース名、ユーザー名、パスワードを指定しています。
本番環境では、これらの値を直接書かず、.env ファイルなどで管理するのがおすすめです。
volumes:
- db_data:/var/lib/postgresql/data
この設定により、PostgreSQLのデータをDocker volumeに保存します。
コンテナを削除してもDBの中身が消えないようにするため、本番運用では必須の設定です。
appコンテナ
app:
build:
context: .
dockerfile: ./containers/django/Dockerfile
app コンテナではDjangoアプリケーションを動かします。
Django用のDockerfileは containers/django/Dockerfile に分けています。
volumes:
- ./app:/code
- static_volume:/code/staticfiles
- media_volume:/code/media
ここでは、Djangoのソースコード、静的ファイル、アップロードファイルをマウントしています。
expose:
- "8000"
expose は、Dockerネットワーク内だけでポートを公開する設定です。
本番環境では、Djangoを直接外部公開せず、Nginx経由でアクセスさせるため、ports ではなく expose を使います。
containers/django/Dockerfile
Djangoアプリケーション用のDockerfileです。
FROM python:3.8
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
WORKDIR /code
# 基本ツール
RUN pip install --upgrade pip && pip install pipenv
# Pipfile / Pipfile.lock の反映
COPY ./Pipfile /code/Pipfile
COPY ./Pipfile.lock /code/Pipfile.lock
COPY . /code/
# pipenv install
RUN pipenv install --system --deploy --ignore-pipfile
# エントリーポイントを登録
COPY ./containers/django/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Gunicornでアプリ起動(runserverではなく)
CMD ["gunicorn", "app.wsgi:application", "--bind", "0.0.0.0:8000"]今回のアプリでは仮想環境としてpipenvを使用しました!
containers/django/entrypoint.sh
entrypoint.sh は、Djangoコンテナ起動時に実行する処理をまとめたファイルです。
#!/bin/sh
python manage.py migrate
python manage.py collectstatic --noinput
gunicorn project.wsgi:application --bind 0.0.0.0:8000主な役割は以下です。
1. マイグレーション実行
2. 静的ファイル収集
3. GunicornでDjangoを起動
migrate
python manage.py migrate
DBのマイグレーションを実行します。
collectstatic
python manage.py collectstatic --noinput
CSSやJavaScriptなどの静的ファイルを STATIC_ROOT に集約します。
Gunicorn起動
gunicorn project.wsgi:application --bind 0.0.0.0:8000
本番環境では、Django標準の runserver ではなく、Gunicornを使って起動します。
nginx/Dockerfile
Nginx用のDockerfileです。
FROM nginx:1.25-alpine
COPY default.conf /etc/nginx/conf.d/default.confNginxの公式イメージをベースにし、独自の設定ファイル default.conf を配置しています。
nginx/default.conf
Nginxの設定ファイルです。
upstream django {
server app:8000;
}
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
client_max_body_size 20M;
location /static/ {
alias /staticfiles/;
}
location /media/ {
alias /media/;
}
location / {
proxy_pass http://django;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}upstream
upstream django {
server app:8000;
}
Docker Compose内では、サービス名で名前解決できます。
そのため、Djangoコンテナには app:8000 でアクセスできます。
proxy_pass
proxy_pass http://django;
ユーザーからのリクエストをDjangoアプリケーションへ転送します。
static / media
location /static/ {
alias /staticfiles/;
}
location /media/ {
alias /media/;
}
静的ファイルやアップロードファイルは、DjangoではなくNginxから配信します。
appディレクトリ
app/
└── Django project
app ディレクトリには、Djangoプロジェクト本体を配置します。
例:
app/
├── manage.py
├── requirements.txt
├── project/
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── application/
├── models.py
├── views.py
└── templates/
dbディレクトリ
db/
db ディレクトリは、バックアップファイルなどを置く用途で使用します。
例:
docker compose exec db pg_dump -U myuser mydb > ./db/backup/backup.sql
PostgreSQLの実データは、基本的にDocker volumeで管理します。
起動方法
docker compose up -d --build
マイグレーション、静的ファイル収集、Gunicorn起動まで entrypoint.sh で実行されます。
本番運用で気をつけたこと
Djangoを直接公開しない
Djangoコンテナでは ports を使わず、expose を使います。
expose:
- "8000"
外部公開するのはNginxだけにします。
DBを永続化する
volumes:
- db_data:/var/lib/postgresql/data
DBのデータはコンテナ内だけに置かず、volumeに保存します。
static / media はNginxで配信する
Djangoに静的ファイル配信を任せるのではなく、Nginxで配信します。
location /static/ {
alias /staticfiles/;
}
開発環境を作成する
この記事では、本番環境へのデプロイ方法についてしか触れていませんが実際の環境では、本番にアップする前にdev.example.comのようにして開発環境にアップしてエラーや挙動などを事前に確認することを強くお勧めします。実際にローカルで確認した際にうまく動いてもデプロイしたらうまくいかないということもよくあるので…
Cloudflareの導入
bot対策やDDOS攻撃の対策の為に、Cloudflareを導入することをお勧めします。
まとめ
今回は、以下の構成でDjangoアプリケーションをDocker Composeによりデプロイする方法を解説しました。
Nginx
↓
Django + Gunicorn
↓
PostgreSQL
この構成にすることで、
・Docker Composeで環境を再現しやすい
・Djangoを直接公開せず安全に運用できる
・PostgreSQLのデータを永続化できる
・静的ファイルをNginxで効率よく配信できる
というメリットがあります。
個人開発のDjangoアプリをVPS上で公開する場合、まずはこの構成をベースにすると扱いやすいと思います。


コメント