Docker Compose avec Django : développement et déploiement
Docker Compose est aujourd'hui l'un des moyens les plus efficaces de développer et de déployer une application Django dans un environnement reproductible. Que vous soyez solo sur un projet ou membre d'une équipe, Docker Compose permet de décrire l'ensemble de votre stack — Django, PostgreSQL, Redis, Nginx — dans un seul fichier YAML, puis de la lancer avec une commande. Cela réduit les écarts entre le développement local, les tests et la production, et facilite l'intégration continue. Dans ce guide, vous allez apprendre à utiliser Docker Compose pour développer et déployer Django, étape par étape, avec des exemples concrets et des bonnes pratiques de production.
- Comprendre le rôle de Docker Compose dans un projet Django moderne.
- Créer un Dockerfile multi-étapes pour le développement et la production.
- Configurer les services web, base de données, cache et reverse proxy.
- Gérer les migrations, les fichiers statiques, les tests et le rechargement automatique.
- Déployer Django avec Docker Compose en respectant les bonnes pratiques de sécurité et de performance.
Pourquoi utiliser Docker Compose pour Django
Django est un framework Python qui dépend de nombreuses bibliothèques, d'une base de données et parfois de services externes. Docker Compose résout le problème de la reproductibilité en isolant chaque service. Vous n'avez plus à installer PostgreSQL, Redis ou Nginx directement sur votre machine. Tout est conteneurisé et décrit dans un fichier docker-compose.yml.
Pour une équipe, l'avantage est immédiat : un nouveau développeur clone le dépôt, lance docker compose up, et obtient le même environnement que les autres. Pour la production, Docker Compose offre une transition douce depuis le développement, même s'il faut adapter la configuration.
Développement local vs production
En développement, on privilégie la rapidité d'itération : montage de volumes, rechargement automatique, serveur Django intégré. En production, on privilégie la robustesse : Gunicorn, Nginx, variables d'environnement sécurisées, journaux centralisés et healthchecks.
Ce que Docker Compose n'est pas
Docker Compose n'est pas un orchestrateur de cluster. Pour plusieurs serveurs, Kubernetes ou Docker Swarm peuvent être plus adaptés. Mais pour un VPS unique ou un déploiement simple, Docker Compose est souvent suffisant et plus facile à maintenir.
Comprendre Docker Compose et Django
Docker Compose est un outil qui permet de définir et de lancer des applications multi-conteneurs. Avec Django, vous aurez généralement au moins deux services : web pour l'application Django et db pour PostgreSQL. Vous pouvez ajouter redis pour le cache ou les files d'attente Celery, et nginx comme reverse proxy en production.
Chaque service est construit à partir d'une image Docker. L'image web est construite à partir d'un Dockerfile qui installe Python, les dépendances et le code de l'application. Les autres services utilisent des images officielles comme postgres:16 ou redis:7.
Le cycle de vie d'une requête Django
En développement, une requête HTTP arrive sur le serveur de développement Django, qui interroge PostgreSQL via le réseau interne de Docker. En production, la requête passe d'abord par Nginx, puis est transmise à Gunicorn, qui exécute Django. Docker Compose crée un réseau partagé pour que les services puissent communiquer par leur nom.
Pourquoi pas seulement Docker ?
Docker seul permet de lancer un conteneur, mais vous devriez gérer manuellement les réseaux, les volumes, les variables d'environnement et l'ordre de démarrage. Docker Compose automatise tout cela dans un fichier déclaratif. C'est particulièrement utile pour les migrations, les tests et les commandes de gestion Django.
Prérequis et installation de Docker Compose
Avant de commencer, assurez-vous d'avoir installé Docker Engine et le plugin Docker Compose. Sur Linux, Docker Compose v2 est inclus avec Docker Desktop ou peut être installé comme plugin. Sur macOS et Windows, Docker Desktop fournit tout le nécessaire.
Vérifiez les versions avec les commandes suivantes.
docker --version
docker compose version
python3 --version
Vous devriez voir Docker 24 ou plus récent, Docker Compose v2.20 ou plus récent, et Python 3.11 ou plus récent. Si vous utilisez une version antérieure, mettez à jour pour bénéficier des dernières fonctionnalités de sécurité et de performance.
Installer Docker sur Ubuntu
Sur Ubuntu, vous pouvez installer Docker depuis le dépôt officiel. Voici les commandes essentielles.
sudo apt update
sudo apt install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable' | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Après l'installation, ajoutez votre utilisateur au groupe docker pour éviter d'utiliser sudo à chaque commande.
sudo usermod -aG docker $USER
newgrp docker
Déconnectez-vous puis reconnectez-vous pour que le changement de groupe soit pris en compte.
Vérifier l'installation
Lancez un conteneur de test pour confirmer que tout fonctionne.
docker run hello-world
Si vous voyez le message de bienvenue, votre installation est prête. Vous pouvez maintenant passer à la structure du projet Django.
Structurer un projet Django compatible Docker Compose
Une bonne structure de projet facilite la conteneurisation. Voici une organisation typique que nous utiliserons dans ce guide.
monprojet/
├── .env
├── .env.example
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
├── docker-compose.prod.yml
├── manage.py
├── requirements.txt
├── config/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── views.py
│ └── migrations/
└── nginx/
└── nginx.conf
Le dossier config contient la configuration Django, tandis que app représente une application métier. Le dossier nginx contient la configuration du reverse proxy pour la production.
Créer le projet Django
Si vous partez de zéro, créez un environnement virtuel local puis installez Django et générez le projet.
python3 -m venv .venv
source .venv/bin/activate
pip install django psycopg2-binary gunicorn
pip freeze > requirements.txt
django-admin startproject config .
La commande django-admin startproject config . crée le projet dans le dossier courant. Cela évite d'avoir un dossier imbriqué supplémentaire.
Le fichier requirements.txt
Pour un projet Django typique avec PostgreSQL et Gunicorn, votre fichier requirements.txt peut ressembler à ceci.
Django==5.0.6
psycopg2-binary==2.9.9
gunicorn==22.0.0
whitenoise==6.6.0
redis==5.0.4
django-redis==5.4.0
celery==5.4.0
Adaptez les versions selon vos besoins. En production, préférez psycopg2-binary uniquement pour le développement ; pour la production, utilisez psycopg2 compilé ou psycopg v3.
Écrire un Dockerfile pour Django
Le Dockerfile décrit comment construire l'image de votre application Django. Pour le développement, nous allons utiliser une image légère basée sur Python slim. Pour la production, nous utiliserons un build multi-étapes afin de réduire la taille de l'image finale.
Dockerfile de développement
Voici un Dockerfile simple pour le développement.
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Ce Dockerfile installe les dépendances système nécessaires à PostgreSQL, copie les requirements, installe les dépendances Python, puis copie le code. La commande CMD lance le serveur de développement Django accessible depuis l'extérieur du conteneur.
Dockerfile de production multi-étapes
En production, nous séparons la construction des dépendances de l'exécution. Cela réduit la taille de l'image et limite la surface d'attaque.
FROM python:3.12-slim AS builder
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH=/home/appuser/.local/bin:$PATH
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --shell /bin/bash appuser
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser . .
USER appuser
EXPOSE 8000
CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]
L'image finale ne contient pas les outils de compilation. Elle utilise un utilisateur non root, ce qui est une bonne pratique de sécurité. Gunicorn est lancé avec trois workers, un nombre que vous ajusterez selon le CPU disponible.
Le fichier .dockerignore
Pour éviter de copier des fichiers inutiles dans l'image, créez un fichier .dockerignore.
.git
.venv
__pycache__
*.pyc
*.pyo
*.pyd
.env
db.sqlite3
media
staticfiles
.vscode
.idea
Cela accélère la construction et évite d'inclure des secrets ou des fichiers locaux.
Configurer docker-compose.yml pour le développement
Le fichier docker-compose.yml décrit les services, les réseaux et les volumes. Voici une configuration complète pour le développement.
services:
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
env_file:
- .env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
postgres_data:
Ce fichier définit trois services : db pour PostgreSQL, redis pour le cache, et web pour Django. Le service web monte le code local dans le conteneur, ce qui permet le rechargement automatique. Le service db utilise un volume nommé pour persister les données.
Comprendre les dépendances et healthchecks
La clé depends_on avec condition: service_healthy garantit que Django ne démarre pas avant que PostgreSQL soit prêt. C'est essentiel pour éviter les erreurs de connexion au démarrage. Le healthcheck utilise pg_isready pour vérifier l'état de la base.
Exposer les ports
En développement, exposez les ports pour accéder à Django sur http://localhost:8000 et à PostgreSQL sur localhost:5432. En production, vous ne devez pas exposer PostgreSQL publiquement. Nous verrons cela plus loin.
Gérer les variables d'environnement avec Docker Compose
Les variables d'environnement sont essentielles pour séparer la configuration du code. Créez un fichier .env à la racine du projet. Ne le commitez jamais dans Git. Ajoutez plutôt un fichier .env.example avec des valeurs fictives.
DEBUG=True
SECRET_KEY=change-me-in-production
ALLOWED_HOSTS=localhost,127.0.0.1
POSTGRES_DB=monprojet
POSTGRES_USER=monprojet
POSTGRES_PASSWORD=motdepasse
DATABASE_URL=postgres://monprojet:motdepasse@db:5432/monprojet
REDIS_URL=redis://redis:6379/0
Dans Django, lisez ces variables avec os.environ ou une bibliothèque comme django-environ. Voici un exemple de configuration dans settings.py.
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key')
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('POSTGRES_DB'),
'USER': os.environ.get('POSTGRES_USER'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
'HOST': os.environ.get('POSTGRES_HOST', 'db'),
'PORT': os.environ.get('POSTGRES_PORT', '5432'),
}
}
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': os.environ.get('REDIS_URL', 'redis://redis:6379/0'),
}
}
Cette configuration fonctionne à la fois en local et dans Docker, car le nom d'hôte de la base est db, le nom du service dans Docker Compose.
Bonnes pratiques pour les secrets
- Ne jamais commiter le fichier
.env. - Utiliser des secrets Docker ou un gestionnaire de secrets en production.
- Définir
DEBUG=Falseen production. - Générer une
SECRET_KEYlongue et aléatoire. - Restreindre
ALLOWED_HOSTSà vos domaines.
Lancer les migrations et créer un superutilisateur Django
Une fois les services démarrés, vous devez appliquer les migrations et créer un superutilisateur. Utilisez docker compose exec pour exécuter des commandes dans le conteneur web.
docker compose up -d
docker compose exec web python manage.py migrate
docker compose exec web python manage.py createsuperuser
La première commande démarre les services en arrière-plan. La deuxième applique les migrations. La troisième crée un compte administrateur. Vous pouvez aussi utiliser docker compose run --rm web python manage.py migrate pour exécuter une commande dans un conteneur temporaire.
Automatiser les migrations au démarrage
Pour éviter d'oublier les migrations, vous pouvez créer un script d'entrée qui attend la base de données puis applique les migrations.
#!/bin/sh
set -e
if [ "$DATABASE_URL" ]; then
echo "Attente de PostgreSQL..."
until pg_isready -h db -p 5432 -U "$POSTGRES_USER"; do
sleep 1
done
fi
python manage.py migrate --noinput
python manage.py collectstatic --noinput
exec "$@"
Ce script peut être utilisé comme entrypoint dans le Dockerfile de production. Il garantit que les migrations sont appliquées avant le lancement de Gunicorn.
Commandes Django utiles
python manage.py makemigrationspour créer les migrations.python manage.py migratepour les appliquer.python manage.py collectstaticpour collecter les fichiers statiques.python manage.py testpour exécuter les tests.python manage.py shellpour ouvrir un shell interactif.
Activer le rechargement automatique et les volumes
En développement, le montage de volume .:/app permet à Django de voir les modifications du code sans reconstruire l'image. Le serveur runserver redémarre automatiquement lorsqu'un fichier Python change.
Pour que cela fonctionne correctement, assurez-vous que le volume est bien monté et que le conteneur utilise le code local. Voici un extrait de docker-compose.yml.
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
Si vous utilisez un système de fichiers différent entre l'hôte et le conteneur, le rechargement peut être lent. Sur macOS et Windows, envisagez d'utiliser cached ou delegated pour améliorer les performances.
Volumes pour les médias et les statiques
En production, les fichiers médias et statiques doivent être persistés en dehors du conteneur. Utilisez des volumes nommés ou des montages de répertoires hôtes.
volumes:
- media_volume:/app/media
- static_volume:/app/staticfiles
Cela permet à Nginx de servir directement ces fichiers sans passer par Django.
Tester et déboguer une application Django sous Docker Compose
Les tests sont essentiels pour garantir la qualité. Avec Docker Compose, vous pouvez exécuter la suite de tests dans un conteneur isolé.
docker compose exec web python manage.py test
Pour utiliser une base de données de test distincte, Django crée automatiquement une base temporaire lors des tests. Assurez-vous que l'utilisateur PostgreSQL a les droits de création de base.
Déboguer avec les logs
Pour voir les logs d'un service, utilisez docker compose logs -f web. Pour suivre tous les services, utilisez docker compose logs -f. Les logs sont essentiels pour diagnostiquer les erreurs de connexion à la base ou les problèmes de migration.
Exécuter un shell dans le conteneur
Pour explorer le conteneur, lancez un shell interactif.
docker compose exec web bash
Vous pouvez alors vérifier les variables d'environnement, les fichiers présents ou lancer des commandes Python manuellement.
Utiliser django-debug-toolbar
En développement, installez django-debug-toolbar et configurez-le pour fonctionner avec Docker. Assurez-vous que INTERNAL_IPS contient l'adresse IP du conteneur ou utilisez host.docker.internal selon votre système.
Préparer la production avec Docker Compose
En production, la configuration diffère sensiblement du développement. Vous devez utiliser Gunicorn, Nginx, des variables d'environnement sécurisées et des healthchecks. Créez un fichier docker-compose.prod.yml qui surcharge le fichier de base.
services:
web:
build:
context: .
dockerfile: Dockerfile
command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 3
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/media
env_file:
- .env.prod
depends_on:
db:
condition: service_healthy
expose:
- "8000"
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env.prod
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
- static_volume:/app/staticfiles
- media_volume:/app/media
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
depends_on:
- web
volumes:
postgres_data:
static_volume:
media_volume:
Ce fichier expose Nginx sur les ports 80 et 443, et garde Django en interne. Les volumes statiques sont partagés entre Django et Nginx.
Configuration Nginx pour Django
Voici un fichier nginx.conf de base pour servir Django et les fichiers statiques.
upstream django {
server web:8000;
}
server {
listen 80;
server_name example.com;
location /static/ {
alias /app/staticfiles/;
}
location /media/ {
alias /app/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;
}
}
Cette configuration transmet les en-têtes nécessaires à Django pour construire des URL absolues et gérer les redirections HTTPS.
Collecter les fichiers statiques
Avant de lancer la production, exécutez collectstatic pour rassembler les fichiers statiques dans le volume partagé.
docker compose -f docker-compose.yml -f docker-compose.prod.yml run --rm web python manage.py collectstatic --noinput
Assurez-vous que STATIC_ROOT est défini sur /app/staticfiles dans settings.py.
Sécuriser un déploiement Django avec Docker Compose
La sécurité est primordiale en production. Voici les points essentiels à vérifier.
- Utiliser
DEBUG=Falseet ne jamais exposer les pages d'erreur détaillées. - Définir une
SECRET_KEYrobuste et unique. - Restreindre
ALLOWED_HOSTSetCSRF_TRUSTED_ORIGINS. - Activer HTTPS avec Let's Encrypt et rediriger HTTP vers HTTPS.
- Ne pas exposer PostgreSQL sur Internet.
- Utiliser un utilisateur non root dans les conteneurs.
- Mettre à jour régulièrement les images de base.
- Scanner les images avec
docker scanou Trivy.
Variables d'environnement et secrets
En production, ne stockez pas les secrets dans le fichier docker-compose.prod.yml. Utilisez des fichiers .env.prod avec des permissions restrictives, ou Docker Secrets si vous utilisez Swarm. Pour un VPS unique, un fichier .env.prod en chmod 600 est un minimum.
Protection contre les attaques courantes
Django inclut des protections contre CSRF, XSS et SQL injection. Assurez-vous que les middlewares sont activés. Ajoutez SECURE_SSL_REDIRECT, SESSION_COOKIE_SECURE et CSRF_COOKIE_SECURE en production.
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Ces paramètres forcent HTTPS et protègent les cookies. Testez-les d'abord en environnement de préproduction.
Optimiser les performances de Django sous Docker Compose
Les performances dépendent de plusieurs facteurs : nombre de workers Gunicorn, cache Redis, requêtes SQL et configuration Nginx. Voici comment optimiser.
Dimensionner Gunicorn
La formule courante est (2 x CPU) + 1 workers. Pour un VPS avec 2 vCPU, utilisez 5 workers. Ajustez avec des tests de charge.
gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 5 --threads 2 --timeout 60
Les threads peuvent aider pour les tâches I/O, mais surveillez la mémoire. Chaque worker consomme de la RAM.
Utiliser Redis pour le cache
Redis réduit la charge sur PostgreSQL. Configurez le cache Django pour les vues coûteuses et les sessions.
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://redis:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
Utilisez cache_page pour les vues publiques et le cache de fragment pour les parties dynamiques.
Optimiser les requêtes SQL
Utilisez select_related et prefetch_related pour éviter le problème N+1. Activez le logging des requêtes lentes en développement pour identifier les goulots d'étranglement.
LOGGING = {
'version': 1,
'handlers': {
'console': {'class': 'logging.StreamHandler'},
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
},
},
}
Ne laissez pas ce niveau en production, car il génère beaucoup de logs.
Intégrer Docker Compose dans un pipeline CI/CD
Docker Compose s'intègre bien dans les pipelines CI/CD. Vous pouvez construire l'image, exécuter les tests, puis déployer sur un serveur. Voici un exemple de workflow GitHub Actions.
name: CI
on:
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and test
run: |
cp .env.example .env
docker compose build
docker compose run --rm web python manage.py test
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /srv/monprojet
git pull
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
docker compose exec -T web python manage.py migrate --noinput
Ce workflow exécute les tests dans un conteneur, puis déploie sur un serveur distant via SSH. Adaptez les secrets et les chemins à votre infrastructure.
Construire et pousser l'image
Pour un déploiement plus robuste, construisez l'image dans la CI et poussez-la vers un registre comme Docker Hub ou GitHub Container Registry. Ensuite, le serveur n'a qu'à tirer l'image.
docker build -t monprojet:latest .
docker tag monprojet:latest registry.example.com/monprojet:latest
docker push registry.example.com/monprojet:latest
Cette approche garantit que l'image testée est exactement celle déployée.
Déployer sur un serveur avec Docker Compose
Pour déployer sur un VPS, installez Docker et Docker Compose, clonez le dépôt, configurez les variables d'environnement, puis lancez les services.
git clone https://github.com/votrecompte/monprojet.git
cd monprojet
cp .env.example .env.prod
nano .env.prod
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
Vérifiez que les services sont démarrés avec docker compose ps. Consultez les logs avec docker compose logs -f.
Configurer un nom de domaine et HTTPS
Pointez votre nom de domaine vers l'adresse IP du serveur. Utilisez Certbot pour générer des certificats Let's Encrypt. Vous pouvez ajouter un service Certbot dans Docker Compose ou l'installer sur l'hôte.
docker run -it --rm --name certbot \
-v ./certbot/conf:/etc/letsencrypt \
-v ./certbot/www:/var/www/certbot \
certbot/certbot certonly --webroot \
--webroot-path=/var/www/certbot \
-d example.com -d www.example.com
Ensuite, configurez Nginx pour utiliser les certificats générés et rediriger le trafic HTTP vers HTTPS.
Mises à jour et rollback
Pour mettre à jour, tirez les dernières modifications, reconstruisez et redémarrez.
git pull
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build
docker compose exec -T web python manage.py migrate --noinput
En cas de problème, revenez à la version précédente avec git checkout et reconstruisez. Gardez toujours une sauvegarde de la base de données avant une migration risquée.
Erreurs courantes et comment les éviter
Voici les erreurs les plus fréquentes lorsque l'on utilise Docker Compose avec Django, et comment les corriger.
- Erreur de connexion à PostgreSQL : Django démarre avant que la base soit prête. Utilisez un healthcheck et
depends_onaveccondition: service_healthy. - Fichiers statiques introuvables : vous avez oublié
collectstaticou le volume n'est pas partagé avec Nginx. - Rechargement automatique inefficace : le volume n'est pas monté ou le serveur tourne sans
runserver. - Migrations non appliquées : exécutez
migrateaprès le démarrage ou automatisez-le dans l'entrypoint. - Secrets exposés : le fichier
.envest commité. Ajoutez-le au.gitignore. - Image trop grosse : vous copiez des fichiers inutiles. Utilisez un
.dockerignoreet un build multi-étapes. - Permissions de fichiers : le conteneur tourne en root et crée des fichiers appartenant à root sur l'hôte. Utilisez un utilisateur non root.
- Port déjà utilisé : un autre service écoute sur 8000 ou 5432. Changez le port ou arrêtez le service conflictuel.
Diagnostiquer les erreurs de build
Si le build échoue, lisez attentivement les premières lignes de l'erreur. Souvent, il s'agit d'une dépendance système manquante comme libpq-dev ou d'un fichier introuvable. Utilisez docker compose build --no-cache pour repartir de zéro.
Erreurs de permission avec les volumes
Sur Linux, l'utilisateur du conteneur peut ne pas avoir les droits d'écriture sur les volumes. Définissez un UID et GID correspondant à votre utilisateur hôte, ou utilisez des volumes nommés.
Bonnes pratiques pour Docker Compose et Django
Adoptez ces bonnes pratiques pour des déploiements fiables et maintenables.
- Séparez les fichiers
docker-compose.ymlde développement et de production. - Utilisez des images de base légères comme
python:3.12-slimoualpine. - Épinglez les versions des dépendances dans
requirements.txt. - Ne stockez jamais de secrets dans le code ou l'image.
- Utilisez des healthchecks pour tous les services critiques.
- Centralisez les logs avec
docker compose logsou un driver de logging. - Surveillez les ressources avec
docker stats. - Automatisez les migrations et
collectstaticdans l'entrypoint. - Testez vos images en local avant de déployer.
- Documentez les commandes de démarrage dans un
README.md.
Nommer les volumes et les réseaux
Docker Compose crée des noms basés sur le nom du projet. Pour éviter les conflits, définissez explicitement name: dans le fichier Compose ou utilisez des variables d'environnement.
name: monprojet
volumes:
postgres_data:
name: monprojet_postgres_data
Cela facilite la gestion des volumes et des sauvegardes.
Sauvegarder la base de données
Automatisez les sauvegardes avec pg_dump dans un conteneur dédié ou via cron sur l'hôte.
docker compose exec -T db pg_dump -U $POSTGRES_USER $POSTGRES_DB > backup_$(date +%Y%m%d).sql
Stockez les sauvegardes en dehors du serveur et testez régulièrement la restauration.
Questions fréquentes sur Docker Compose et Django
Docker Compose est-il adapté à la production Django ?
Oui, pour un serveur unique ou un petit cluster, Docker Compose est tout à fait adapté. Il gère le cycle de vie des conteneurs, les redémarrages et les dépendances. Pour une scalabilité horizontale avancée, Kubernetes ou Swarm sont plus appropriés.
Comment exécuter les migrations automatiquement au démarrage ?
Utilisez un script d'entrée qui attend la base de données puis lance python manage.py migrate --noinput. Placez ce script comme ENTRYPOINT dans le Dockerfile de production.
Pourquoi mes fichiers statiques ne sont-ils pas servis ?
En production, Django ne sert pas les fichiers statiques. Vous devez exécuter collectstatic et configurer Nginx pour servir le dossier staticfiles. Vérifiez que le volume est partagé entre les services web et nginx.
Comment gérer les médias uploadés par les utilisateurs ?
Montez un volume pour /app/media et configurez Nginx pour servir ce dossier. En production, envisagez un stockage objet comme Amazon S3 ou MinIO pour éviter de dépendre du disque local.
Puis-je utiliser SQLite avec Docker Compose et Django ?
Oui, mais SQLite est déconseillé en production. Pour le développement, vous pouvez monter un volume pour le fichier db.sqlite3. Pour la production, utilisez PostgreSQL ou MySQL.
Comment réduire la taille de l'image Docker ?
Utilisez un build multi-étapes, une image de base slim ou alpine, et un fichier .dockerignore. Ne copiez que les fichiers nécessaires et nettoyez le cache apt après l'installation.
Comment déboguer un conteneur qui ne démarre pas ?
Consultez les logs avec docker compose logs web. Vérifiez les variables d'environnement, les dépendances et les permissions. Vous pouvez aussi lancer un shell avec docker compose run --rm web bash.
Docker Compose fonctionne-t-il avec Django Channels et WebSockets ?
Oui, mais vous devez utiliser Daphne ou Uvicorn au lieu de Gunicorn, et configurer Nginx pour proxy les connexions WebSocket. Ajoutez les en-têtes Upgrade et Connection dans la configuration Nginx.
Prochaines étapes pour maîtriser Docker Compose avec Django
Vous avez maintenant une base solide pour développer et déployer Django avec Docker Compose. Pour aller plus loin, explorez les sujets suivants.
- Ajoutez Celery et Redis pour les tâches asynchrones.
- Intégrez un stockage objet pour les médias.
- Mettez en place une supervision avec Prometheus et Grafana.
- Automatisez les sauvegardes et les tests de restauration.
- Utilisez des secrets Docker ou Vault pour la gestion des secrets.
- Testez le déploiement sur un environnement de préproduction.
Commencez par conteneuriser un petit projet Django, puis ajoutez progressivement les services. La clé est de garder la configuration simple, de versionner les fichiers et de ne jamais commiter de secrets. Avec Docker Compose, vous obtenez un environnement reproductible qui accélère le développement et sécurise le déploiement de Django.