Retour au cours

infra / docker

Docker Compose : orchestrer plusieurs conteneurs

Leçon 81 exercice

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_on avec condition: service_healthy pour 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 down de docker compose down -v et 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.

CommandeEffet
docker compose up -dConstruit (si besoin) et lance toute la stack en arrière-plan
docker compose downArrête et supprime conteneurs + réseau
docker compose down -vIdem, + supprime aussi les volumes (perte de données !)
docker compose logs -f apiLogs 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

yaml
# 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:
bash
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=3

Résumé

  • depends_on avec condition: service_healthy attend 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 -v supprime aussi les volumes : à réserver aux environnements jetables (dev/test).

Exercices pratiques

1 disponible
1

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".

Résoudre l’exercice →