🎯 Objectif : À la fin de ce chapitre, tu sauras orchestrer des applications multi-conteneurs avec Docker Compose — définir des services, gérer réseaux et volumes, et lancer une stack complète en une commande. ⏱️ Durée estimée : 50 minutes | Niveau : Intermédiaire
Jusqu’ici, tu lançais tes conteneurs un par un avec docker run. Ça marche pour un conteneur isolé, mais dans la vraie vie, une application c’est rarement un seul process. Tu as un backend, une base de données, un cache, peut-être un reverse proxy. Lancer tout ça manuellement avec les bons flags, les bons réseaux, les bons volumes — c’est fastidieux et source d’erreurs.
Docker Compose résout ce problème. Tu décris ta stack entière dans un fichier YAML, et une seule commande fait tout tourner. C’est l’outil qui transforme une série de commandes docker run en infrastructure déclarative, versionnée, reproductible.
Pourquoi Docker Compose change la donne
Sans Compose, démarrer une stack de 3 conteneurs implique de créer un réseau, lancer chaque conteneur avec une dizaine de flags, gérer l’ordre de démarrage manuellement, et documenter tout ça quelque part pour que ton collègue puisse reproduire. Spoiler : il n’y arrivera pas du premier coup.
Avec Compose, tu obtiens :
- Un fichier = une stack — tout est versionné dans Git, lisible par n’importe qui
- Une commande —
docker compose uplance l’ensemble - Isolation par projet — chaque stack a ses propres réseaux et volumes
- Reproductibilité — même comportement en dev, en CI et en staging
🔥 Cas réel : Une équipe de 8 développeurs perdait 30 minutes par personne à chaque onboarding pour configurer l’environnement local. Après migration vers un docker-compose.yml partagé : git clone + docker compose up = environnement prêt en 2 minutes. Sur un mois, c’est des heures récupérées.
Docker Compose est intégré au CLI Docker moderne. La commande est
docker compose(sans tiret). L’ancien binairedocker-composeavec tiret est déprécié.
Comprendre la structure d’un fichier Compose
Un fichier docker-compose.yml s’articule autour de trois blocs. Voici le squelette minimal que tu retrouveras dans tous tes projets :
services: # Les conteneurs à lancer
api:
image: python:3.12-slim
ports:
- "5000:5000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/app
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 5s
retries: 5
volumes: # Les volumes persistants
pg-data:
networks: # Les réseaux (optionnel, un réseau par défaut est créé)
default:
driver: bridge
Quelques points essentiels à retenir :
- Le nom du service devient un hostname DNS. Ton service
dbest joignable par les autres conteneurs viadb:5432. Pas besoin d’IP, Docker gère la résolution automatiquement. depends_onaveccondition: service_healthygarantit que PostgreSQL est réellement prêt avant de lancer l’API — pas juste démarré, mais fonctionnel.- Les volumes nommés (
pg-data) survivent auxdocker compose down. Les données persistent entre les redémarrages.
💡 Tip DevOps : Ne hardcode jamais les mots de passe dans le YAML. Utilise un fichier .env à la racine du projet. Compose le lit automatiquement. Ajoute .env dans ton .gitignore — toujours.
Commandes essentielles
Tu vas utiliser ces commandes quotidiennement. Voici les incontournables avec leur contexte d’usage :
# Lancer toute la stack en arrière-plan
docker compose up -d
# Voir les logs en temps réel (tous les services)
docker compose logs -f
# Voir les logs d'un seul service
docker compose logs -f api
# Vérifier l'état des conteneurs
docker compose ps
# Arrêter et supprimer les conteneurs (volumes conservés)
docker compose down
# Tout supprimer, y compris les volumes (⚠️ données perdues)
docker compose down -v
# Rebuild après modification du Dockerfile
docker compose up -d --build
⚠️ Attention : docker compose down -v supprime les volumes nommés. En production, c’est la perte de ta base de données. Utilise cette commande uniquement en développement pour repartir de zéro.
🧠 À retenir : docker compose up -d --build est la commande réflexe après toute modification de code ou de Dockerfile. Sans --build, Compose réutilise l’ancienne image et tu te demanderas pourquoi tes changements ne s’appliquent pas.
Cas concret : stack d’entreprise API + PostgreSQL + Redis
Passons à un cas réaliste. Imagine une API Flask avec une base PostgreSQL pour le stockage et Redis pour le cache. Voici le docker-compose.yml complet que tu pourrais trouver dans un vrai projet :
services:
api:
build: ./api
ports:
- "${API_PORT:-5000}:5000"
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- pg-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
retries: 5
restart: unless-stopped
volumes:
pg-data:
redis-data:
Et le fichier .env correspondant à placer à la racine :
POSTGRES_USER=appuser
POSTGRES_PASSWORD=s3cur3_p@ss
POSTGRES_DB=myapp
API_PORT=5000
Décortiquons les choix importants :
restart: unless-stopped— les conteneurs redémarrent automatiquement après un crash ou un reboot du serveur, sauf si tu les arrêtes explicitement.start_period: 10ssur PostgreSQL — laisse le temps à la base de s’initialiser avant de commencer les checks de santé. Sans ça, les premiers échecs comptent comme des vrais problèmes.:rosur le bind mount du script SQL — le conteneur ne peut que lire le fichier. Principe du moindre privilège.--maxmemory-policy allkeys-lrusur Redis — quand la mémoire est pleine, les clés les moins utilisées sont évincées automatiquement. Indispensable en production.
🔥 Cas réel : Un développeur avait oublié le start_period sur PostgreSQL. Résultat : au premier démarrage, la base prenait 15 secondes pour initialiser les données, le healthcheck échouait 5 fois, et Compose marquait le service comme unhealthy. L’API refusait de démarrer. Un simple start_period: 20s a résolu le problème.
Pièges fréquents
1. depends_on sans healthcheck — Par défaut, depends_on attend juste que le conteneur soit démarré, pas qu’il soit prêt. Ton API va tenter de se connecter à PostgreSQL alors que celui-ci initialise encore ses tables. Toujours utiliser condition: service_healthy.
2. Oublier --build après un changement — Tu modifies ton code Python, tu relances docker compose up -d… et rien ne change. Compose a gardé l’ancienne image en cache. Ajoute --build.
3. Ports en conflit — Deux stacks Compose qui exposent le même port sur l’hôte = erreur. Utilise des variables d’environnement (${API_PORT:-5000}) pour rendre les ports configurables.
4. Volumes orphelins qui s’accumulent — Chaque docker compose down sans -v conserve les volumes. Au bout de quelques semaines, tu as des dizaines de volumes inutilisés. Nettoie régulièrement avec docker volume prune.
5. Fichier .env commité dans Git — Tes mots de passe finissent sur GitHub. Ajoute .env dans .gitignore et fournis un .env.example avec des valeurs placeholder.
⚠️ Attention : En production, ne mets jamais de secrets dans le fichier .env ou le YAML directement. Utilise Docker Secrets ou un gestionnaire de secrets externe (Vault, AWS Secrets Manager). Le .env c’est pour le développement local uniquement.
Exercice pratique
Crée une stack de monitoring minimaliste :
- Un service Prometheus (image
prom/prometheus) exposé sur le port 9090, avec un fichier de config monté en bind mount - Un service Grafana (image
grafana/grafana) exposé sur le port 3000, qui dépend de Prometheus - Un volume nommé pour les données Grafana
- Un healthcheck sur chaque service
Objectifs :
- Grafana ne doit démarrer qu’une fois Prometheus healthy
- Les données Grafana doivent persister après un
docker compose down - Vérifie que tu accèdes à Grafana sur
http://localhost:3000
💡 Tip DevOps : Pour le healthcheck Prometheus, utilise wget --spider http://localhost:9090/-/healthy. Pour Grafana : curl -f http://localhost:3000/api/health.
🧠 À retenir
🧠 Les points clés de ce chapitre :
- Docker Compose = infrastructure déclarative dans un fichier YAML. Un fichier, une commande, toute ta stack tourne.
- Les noms de services sont des hostnames DNS — pas besoin d’IP, les conteneurs se trouvent par leur nom.
- Healthchecks +
condition: service_healthy= la bonne manière de gérer les dépendances entre services.depends_onseul ne suffit pas. - Volumes nommés pour les données persistantes, bind mounts pour le code en développement.
.env+.gitignore= la base pour gérer les secrets en local. En production, utilise de vrais outils de gestion de secrets.docker compose up -d --build= ta commande réflexe après tout changement.
➡️ La suite : Dans le prochain chapitre, on explore les fonctionnalités avancées de Compose — profiles, override files et stratégies de déploiement. On continue ! 🚀
🖥️ Pratique sur ton propre serveur
Pour suivre Apprendre Docker en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Apprendre Docker
5 / 10- Pourquoi Docker ? Les conteneurs expliqués
- Tes premières commandes Docker
- Ton premier Dockerfile
- Dockerfile avancé : multi-stage et optimisation
- 5 Docker Compose : orchestrer tes services
- 6 Compose avancé : volumes, réseaux et scaling
- 7 Docker en production : logs et healthchecks
- 8 Déploiement et CI/CD avec Docker
- 9 Sécurité Docker : rootless et isolation
- 10 Scanning et conformité Docker
Sur cette page
Articles liés
Pourquoi Docker ? Les conteneurs expliqués
Découvre ce que sont les conteneurs, comment ils se distinguent des machines virtuelles et comprends l'architecture Docker.
Tes premières commandes Docker
Prends en main Docker avec tes premières commandes : docker run, pull, ps, images, exec et le cycle de vie des conteneurs.
Ton premier Dockerfile
Apprends à écrire un Dockerfile avec les instructions essentielles : FROM, COPY, RUN, CMD et docker build.