Module Technique 2 — Docker Compose

Orchestrer plusieurs conteneurs pour des applications complexes

docker
compose
mlops
Auteur·rice

François Boussengui

Date de publication

24 mars 2026

0.0.1 🎯 Objectifs d’apprentissage

À l’issue de ce module, tu seras capable de :

  1. Expliquer pourquoi on a besoin d’orchestrer plusieurs conteneurs
  2. Écrire un fichier docker-compose.yml complet
  3. Configurer services, réseaux et volumes dans Compose
  4. Déployer une application multi-conteneurs (API + BDD)
  5. Maîtriser les commandes Compose du quotidien

📚 Prérequis : Module Technique 1 — Docker installé et bases maîtrisées

⏱️ Temps estimé : 3 heures


1 Pourquoi Docker Compose ?

1.1 Le problème des applications multi-services

En pratique, une application Data Science ne tourne jamais seule. Elle a besoin de services complémentaires :

flowchart LR
    A[🐍 API Python<br>FastAPI/Flask] --> B[🗄️ Base de données<br>PostgreSQL]
    A --> C[📊 Dashboard<br>Streamlit]
    A --> D[💾 Cache<br>Redis]
    C --> A

Architecture typique d’une application Data Science

Sans Compose, il faudrait lancer manuellement chaque conteneur avec de longues commandes docker run. Compose permet de tout définir dans un seul fichier YAML.

1.2 Structure du fichier docker-compose.yml

# docker-compose.yml
version: "3.8"

services:
  api:
    build: ./api
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/assurance
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: assurance
    volumes:
      - pg_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  pg_data:

💡 Point clé

Dans Compose, les services communiquent entre eux par leur nom de service. Ici, l’API accède à la BDD via db:5432 — pas besoin d’adresse IP. Compose crée automatiquement un réseau interne.


2 Les concepts clés de Compose

2.1 Services

Un service = un conteneur (ou plusieurs réplicas) défini par une image ou un build context.

Propriété Description
image Image Docker à utiliser
build Chemin vers un Dockerfile
ports Mapping de ports host:conteneur
environment Variables d’environnement
depends_on Ordre de démarrage
volumes Montages de données
restart Politique de redémarrage

2.2 Volumes

Les volumes persistent les données au-delà du cycle de vie des conteneurs :

volumes:
  pg_data:           # Volume nommé (géré par Docker)

services:
  db:
    volumes:
      - pg_data:/var/lib/postgresql/data  # Volume nommé
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # Bind mount

2.3 Réseaux

Par défaut, Compose crée un réseau pour chaque projet. Tu peux aussi définir des réseaux personnalisés pour isoler certains services.


3 Application pratique : API + PostgreSQL

3.1 Structure du projet

projet-assurance/
├── docker-compose.yml
├── api/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── main.py
└── db/
    └── init.sql

3.2 Le Dockerfile de l’API

FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

3.3 Le script API (main.py)

from fastapi import FastAPI
import psycopg2
import os

app = FastAPI(title="API Assurance")

@app.get("/contrats")
def get_contrats():
    conn = psycopg2.connect(os.environ["DATABASE_URL"])
    cur = conn.cursor()
    cur.execute("SELECT * FROM contrats LIMIT 10")
    rows = cur.fetchall()
    conn.close()
    return {"contrats": rows}

4 Les commandes essentielles

Commande Description
docker compose up Démarrer tous les services
docker compose up -d Démarrer en arrière-plan
docker compose down Arrêter et supprimer les conteneurs
docker compose logs -f Suivre les logs en temps réel
docker compose ps Lister les services en cours
docker compose exec api bash Entrer dans un service
docker compose build Reconstruire les images

# Lancer l’application
\(</span> docker compose up -d<br> <span class="output">[+] Running 3/3</span><br> <span class="output"> ✔ Network projet_default Created</span><br> <span class="output"> ✔ Container projet-db-1 Started</span><br> <span class="output"> ✔ Container projet-api-1 Started</span><br><br> <span class="comment"># Vérifier que tout tourne</span><br> <span class="prompt">\) docker compose ps
NAME SERVICE STATUS PORTS
projet-api-1 api running 0.0.0.0:8000->8000/tcp
projet-db-1 db running 0.0.0.0:5432->5432/tcp


5 Bonnes pratiques

5.0.0.1 ❌ À éviter

  • Mettre les mots de passe en dur dans le YAML
  • Ne pas utiliser depends_on
  • Oublier les volumes pour les données persistantes
  • Utiliser latest comme tag d’image

5.0.0.2 ✅ Recommandé

  • Utiliser un fichier .env pour les secrets
  • Définir l’ordre de démarrage
  • Toujours persister les données de BDD
  • Fixer les versions d’images

⚠️ Important

depends_on ne garantit pas que le service est prêt, seulement qu’il est démarré. Pour PostgreSQL, utilise un healthcheck ou un script d’attente dans ton API.


Synthèse

5.0.1 🎯 Les 5 points essentiels

  1. Compose orchestre plusieurs conteneurs — Un fichier YAML pour toute l’architecture
  2. Les services communiquent par nom — Pas besoin d’IP, Compose gère le réseau
  3. Les volumes persistent les données — Indispensable pour les bases de données
  4. depends_on gère l’ordre — Mais pas la disponibilité réelle du service
  5. Le fichier .env protège les secrets — Ne jamais commiter les mots de passe

Auto-évaluation

Réponse : docker run lance un seul conteneur à partir d’une image. docker compose up lance tous les services définis dans le fichier docker-compose.yml, avec leurs réseaux, volumes et dépendances configurés.

Réponse : Par le nom du service défini dans le YAML. Compose crée automatiquement un réseau interne et un DNS. Exemple : l’API accède à PostgreSQL via db:5432 (où db est le nom du service).

Réponse : Un volume nommé est géré par Docker, offrant de meilleures performances et une portabilité accrue. Un bind mount lie un dossier de l’hôte au conteneur — utile en développement, mais moins portable. Pour les données de production (BDD), un volume nommé est préférable.

Réponse : Non. depends_on garantit uniquement que le conteneur est démarré, pas que le service à l’intérieur est opérationnel. PostgreSQL peut prendre quelques secondes pour s’initialiser. Il faut ajouter un healthcheck ou un mécanisme de retry dans l’application.


← Retour à la Semaine 2 Voir la Fiche de travail →