infra / docker
Docker Compose : orchestrer plusieurs conteneurs
Explication
Ce que vous allez apprendre
- Décrire une pile multi-conteneurs complète dans un unique fichier
docker-compose.yml - Comprendre la différence entre une approche déclarative et une suite de commandes impératives
- Utiliser
depends_onaveccondition: service_healthypour attendre qu'un service soit réellement prêt - Piloter le cycle de vie complet d'une stack (
up,down,logs,exec,restart) - Distinguer
docker compose downdedocker compose down -vet le risque de perte de données du second
Dans quel contexte ?
Une équipe de développement doit onboarder un nouveau développeur qui doit lancer localement une API, une base PostgreSQL et un cache Redis. Sans Compose, il faudrait lui transmettre une liste de commandes docker run à exécuter dans le bon ordre, avec le bon réseau. Avec un fichier docker-compose.yml versionné dans le repo, une seule commande (docker compose up -d) suffit à reproduire exactement le même environnement, sans qu'il ait besoin de comprendre tous les détails de configuration.
Le problème des commandes qui s'accumulent
Une application réelle est rarement un seul conteneur isolé : elle combine typiquement une API, une base de données, un cache. Lancer chaque conteneur à la main avec de longues commandes docker run, dans le bon ordre, avec le bon réseau, devient vite pénible et source d'erreurs. Docker Compose répond à ce problème en permettant de décrire toute cette pile applicative dans un unique fichier déclaratif (docker-compose.yml), puis de la démarrer ou l'arrêter d'un seul coup.
| Commande | Effet |
|---|---|
docker compose up -d | Construit (si besoin) et lance toute la stack en arrière-plan |
docker compose down | Arrête et supprime conteneurs + réseau |
docker compose down -v | Idem, + supprime aussi les volumes (perte de données !) |
docker compose logs -f api | Logs d'un service précis, en temps réel |
Prérequis
Cette leçon suppose que tu es à l'aise avec les réseaux Docker personnalisés (leçon précédente) et les healthchecks conceptuellement : Compose s'appuie directement sur ces deux notions.
Déclaratif plutôt qu'impératif
C'est le changement d'état d'esprit important de cette leçon : au lieu de décrire une suite d'actions ("lance ceci, puis cela"), on décrit l'état voulu ("voici les services, leurs images, leurs ports, leurs volumes"), et Compose se charge de faire converger la réalité vers cette description. C'est beaucoup plus facile à relire, à versionner dans Git et à partager avec une équipe qu'une série de commandes.
depends_on ne suffit pas toujours
Un piège classique : depends_on seul garantit seulement l'ORDRE de démarrage des conteneurs, pas que le service dépendant soit réellement prêt à recevoir des requêtes. Une base de données peut mettre plusieurs secondes à accepter des connexions après son démarrage. C'est pour cela qu'on combine depends_on avec une condition service_healthy, qui attend qu'un healthcheck (vu en détail dans une leçon dédiée) confirme que le service répond correctement, pas seulement qu'il a démarré.
Réseau automatique entre services
Compose crée automatiquement un réseau partagé entre les services d'un même fichier, avec résolution de noms intégrée : un service peut joindre un autre simplement par son nom déclaré dans le fichier (db, cache...), exactement comme vu dans la leçon sur les réseaux personnalisés.
Attention à down -v
Le -v supprime aussi les volumes, donc les données persistées.
Piège dangereux
docker compose down -v est une commande à réserver strictement aux environnements jetables (dev/test), jamais à taper par réflexe en production. Une seule exécution malencontreuse peut effacer irrémédiablement toutes les données d'une base de données qui tournait dans la stack.
Commandes & code
Docker Compose
# docker-compose.yml : décrit une stack multi-conteneurs en un seul fichier déclaratif
services:
api:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://app:app@db:5432/app
- REDIS_URL=redis://cache:6379/0
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks:
- backend
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=app
- POSTGRES_PASSWORD=app
- POSTGRES_DB=app
volumes:
- data_postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 3s
retries: 5
networks:
- backend
cache:
image: redis:7-alpine
networks:
- backend
volumes:
data_postgres:
networks:
backend:docker compose up # construit (si besoin) et lance toute la stack au premier plan
docker compose up -d # en arrière-plan
docker compose up -d --build # force la reconstruction des images avant de lancer
docker compose ps # état des services de la stack
docker compose logs -f api # logs d'un service précis, en temps réel
docker compose exec api bash # shell dans un service en cours d'exécution
docker compose stop # arrête tous les services (garde les conteneurs)
docker compose down # arrête ET supprime conteneurs + réseau
docker compose down -v # + supprime aussi les volumes (perte de données !)
docker compose restart api # redémarre uniquement le service "api"
docker compose config # valide et affiche la config finale résolue
# Surcharge d'environnement (dev vs prod) avec plusieurs fichiers compose
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Mise à l'échelle locale d'un service (utile pour tester un load balancing simple)
docker compose up -d --scale api=3Résumé
depends_onaveccondition: service_healthyattend qu'un healthcheck passe, pas juste que le conteneur démarre.- Un réseau custom (
backend) permet aux services de se joindre par leur nom de service (db,cache). docker compose down -vsupprime aussi les volumes : à réserver aux environnements jetables (dev/test).
Exercices pratiques
Mission : fiabiliser l'onboarding d'un nouveau développeur avec Compose
Objectif : Écrire un fichier Compose robuste qui attend réellement que la base soit prête, et éviter la perte de données au nettoyage.
Contexte
Un nouveau développeur a lancé la stack avec docker compose up -d, mais son API plante au démarrage car elle tente de se connecter à la base avant qu'elle accepte des connexions. Il a aussi failli lancer docker compose down -v par réflexe pour "tout nettoyer".