Docker Compose avec Django : développement et déploiement

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=False en production.
  • Générer une SECRET_KEY longue 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

  1. python manage.py makemigrations pour créer les migrations.
  2. python manage.py migrate pour les appliquer.
  3. python manage.py collectstatic pour collecter les fichiers statiques.
  4. python manage.py test pour exécuter les tests.
  5. python manage.py shell pour 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=False et ne jamais exposer les pages d'erreur détaillées.
  • Définir une SECRET_KEY robuste et unique.
  • Restreindre ALLOWED_HOSTS et CSRF_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 scan ou 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_on avec condition: service_healthy.
  • Fichiers statiques introuvables : vous avez oublié collectstatic ou 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 migrate après le démarrage ou automatisez-le dans l'entrypoint.
  • Secrets exposés : le fichier .env est commité. Ajoutez-le au .gitignore.
  • Image trop grosse : vous copiez des fichiers inutiles. Utilisez un .dockerignore et 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.

  1. Séparez les fichiers docker-compose.yml de développement et de production.
  2. Utilisez des images de base légères comme python:3.12-slim ou alpine.
  3. Épinglez les versions des dépendances dans requirements.txt.
  4. Ne stockez jamais de secrets dans le code ou l'image.
  5. Utilisez des healthchecks pour tous les services critiques.
  6. Centralisez les logs avec docker compose logs ou un driver de logging.
  7. Surveillez les ressources avec docker stats.
  8. Automatisez les migrations et collectstatic dans l'entrypoint.
  9. Testez vos images en local avant de déployer.
  10. 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.

#docker compose #django #docker #développement #déploiement #python #devops #postgresql #nginx #gunicorn #conteneurisation #web development

Subscribe to our newsletter

12k+

Subscribers

Weekly

Frequency

Free

Always