Aller au contenu principal
DockerConteneursFormation

Docker Compose : orchestrer tes services

30 min de lecture Apprendre Docker — Chapitre 5

Découvre Docker Compose : docker-compose.yml, services, up/down et ton premier projet multi-conteneurs.

🎯 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 commandedocker compose up lance 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 binaire docker-compose avec 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 db est joignable par les autres conteneurs via db:5432. Pas besoin d’IP, Docker gère la résolution automatiquement.
  • depends_on avec condition: service_healthy garantit 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 aux docker 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: 10s sur 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.
  • :ro sur le bind mount du script SQL — le conteneur ne peut que lire le fichier. Principe du moindre privilège.
  • --maxmemory-policy allkeys-lru sur 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 :

  1. Un service Prometheus (image prom/prometheus) exposé sur le port 9090, avec un fichier de config monté en bind mount
  2. Un service Grafana (image grafana/grafana) exposé sur le port 3000, qui dépend de Prometheus
  3. Un volume nommé pour les données Grafana
  4. 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_on seul 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.

Obtenir 200$

Articles liés