Docker pour les devs - 09 - Docker Compose, les bases

Orchestrer plusieurs conteneurs avec Docker Compose : services, ports, depends_on et un vrai exemple app + db + redis.

  1. 01 Docker pour les devs - 00 - Pourquoi Docker change tout
  2. 02 Docker pour les devs - 01 - Containers vs VMs
  3. 03 Docker pour les devs - 02 - L'architecture de Docker
  4. 04 Docker pour les devs - 03 - Docker Desktop, Engine et alternatives
  5. 05 Docker pour les devs - 04 - Écrire un Dockerfile
  6. 06 Docker pour les devs - 05 - Layers et cache
  7. 07 Docker pour les devs - 06 - Le .dockerignore
  8. 08 Docker pour les devs - 07 - Multi-stage builds
  9. 09 Docker pour les devs - 08 - Choisir son image de base
  10. 10 Docker pour les devs - 09 - Docker Compose, les bases
  11. 11 Docker pour les devs - 10 - Docker Compose avance
  12. 12 Docker pour les devs - 11 - Networking Docker, les bases
  13. 13 Docker pour les devs - 12 - Networking Docker avance
  14. 14 Docker pour les devs - 13 - Volumes et persistance
  15. 15 Docker pour les devs - 14 - Variables d'environnement et secrets
  16. 16 Docker pour les devs - 15 - Permissions et utilisateurs
  17. 17 Docker pour les devs - 16 - Docker et monorepo
  18. 18 Docker pour les devs - 17 - Dev vs Prod
  19. 19 Docker pour les devs - 18 - ENTRYPOINT, CMD et scripts d'initialisation
  20. 20 Docker pour les devs - 19 - Debugger ses conteneurs
  21. 21 Docker pour les devs - 20 - Bases de donnees dans Docker
  22. 22 Docker pour les devs - 21 - Sauvegardes et restauration
  23. 23 Docker pour les devs - 22 - Conteneuriser un frontend
  24. 24 Docker pour les devs - 23 - Sécurité des conteneurs
  25. 25 Docker pour les devs - 24 - Optimisation des images
  26. 26 Docker pour les devs - 25 - Builds multi-platform
  27. 27 Docker pour les devs - 26 - Limiter les ressources de tes conteneurs
  28. 28 Docker pour les devs - 27 - Gerer les logs comme un adulte
  29. 29 Docker pour les devs - 28 - Healthchecks et restart policies
  30. 30 Docker pour les devs - 29 - Nettoyer Docker avant qu'il mange ton disque
  31. 31 Docker pour les devs - 30 - Registries et stratégie de tags
  32. 32 Docker pour les devs - 31 - Docker en CI/CD
  33. 33 Docker pour les devs - 32 - Au-dela de Compose
  34. 34 Docker pour les devs - 33 - Glossaire Docker de A a Z

09 - Docker Compose, les bases

Ce que tu vas apprendre

  • Ce qu'est Docker Compose et pourquoi tu en as besoin
  • Les directives principales : services, build, image, ports, depends_on, command
  • Les commandes du quotidien : up, down, logs, ps
  • La différence entre compose.yaml et docker-compose.yml
  • Un vrai exemple avec app + base de donnees + redis

Prerequisites


Le jour ou tu lances ta première commande docker run avec 15 flags, tu te dis que ca ne va pas tenir. Et tu as raison. Docker Compose existe pour ca : decrire toute ton infrastructure locale dans un fichier YAML, et la démarrer en une commande.

Pourquoi Compose existe

Sur paltemps.fr, j'ai trois services qui tournent ensemble : un serveur Node, une base PostgreSQL et un cache Redis. Sans Compose, je devrais lancer trois docker run avec les bons réseaux, les bons volumes, les bonnes variables d'environnement. Et recommencer a chaque redemarrage.

Compose transforme ces commandes en un fichier declaratif. Tu decris ce que tu veux, Docker s'occupe du reste.

Le fichier compose.yaml

Docker a change le nom du fichier plusieurs fois. Aujourd'hui, la convention officielle c'est compose.yaml. Les anciens noms docker-compose.yml et docker-compose.yaml fonctionnent toujours, mais Compose v2 cherche compose.yaml en priorité.

Un fichier minimal :

yamlservices:
  app:
    build: .
    ports:
      - "3000:3000"

C'est tout. Un service nomme app, construit depuis le Dockerfile du répertoire courant, avec le port 3000 expose.

Les directives de base

build vs image

Tu as deux facons de spécifier d'ou vient ton conteneur :

yamlservices:
  # Construire depuis un Dockerfile local
  app:
    build:
      context: .
      dockerfile: Dockerfile

  # Utiliser une image existante
  db:
    image: postgres:16-alpine

build construit l'image. image la telecharge. Tu ne peux pas utiliser les deux sur le meme service (sauf si tu veux nommer l'image construite).

ports

Le mapping de ports suit le format host:container :

yamlservices:
  app:
    ports:
      - "3000:3000"    # host 3000 -> container 3000
      - "9229:9229"    # debugger Node

depends_on

depends_on dit a Compose de démarrer les services dans le bon ordre :

yamlservices:
  app:
    depends_on:
      - db
      - redis
  db:
    image: postgres:16-alpine
  redis:
    image: redis:7-alpine

Attention : depends_on attend que le conteneur démarré, pas qu'il soit pret. PostgreSQL peut mettre quelques secondes a accepter les connexions apres le démarrage du conteneur. Pour ca, tu peux ajouter une condition :

yamlservices:
  app:
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

command

command remplace le CMD du Dockerfile :

yamlservices:
  app:
    build: .
    command: node --watch src/index.js

Pratique pour changer le comportement en dev sans modifier le Dockerfile.

Un vrai exemple : app + db + redis

Voici un compose.yaml complet et realiste :

yamlservices:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://postgres:secret@db:5432/myapp
      REDIS_URL: redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:

Remarque le DATABASE_URL : le hostname db correspond au nom du service. Compose créé un réseau interne et chaque service est accessible par son nom. On verra ca en détail dans l'article sur le networking.

Les commandes du quotidien

Démarrer les services

bashdocker compose up

Ca construit les images si besoin et démarré tout. Ajoute -d pour le mode detache (en arriere-plan) :

bashdocker compose up -d

Et --build pour forcer la reconstruction :

bashdocker compose up -d --build

Voir les logs

bashdocker compose logs         # tous les services
docker compose logs app     # un seul service
docker compose logs -f app  # suivre en temps reel

Voir l'état des services

bashdocker compose ps

Ca affiche chaque service, son état, et les ports mappes.

Arreter tout

bashdocker compose down

Les conteneurs sont supprimes, mais les volumes sont conserves. Pour tout supprimer, y compris les volumes :

bashdocker compose down -v

J'utilise down -v rarement. Perdre les donnees de la base en dev, c'est souvent penible.

Redemarrer un service spécifique

bashdocker compose restart app

L'erreur classique du débutant

Je la vois tout le temps : utiliser docker-compose (avec un tiret) au lieu de docker compose (avec un espace). L'ancien binaire docker-compose est deprecated depuis Compose v2. La bonne commande, c'est docker compose, intégré directement dans la CLI Docker.

Si docker compose version ne renvoie rien, c'est que le plugin n'est pas installe. Avec Docker Desktop, il l'est par défaut.

Résumé

  • compose.yaml decrit tes services, leurs images, ports, dépendances et volumes
  • build construit depuis un Dockerfile, image utilise une image existante
  • depends_on avec condition: service_healthy attend que le service soit vraiment pret
  • docker compose up -d --build est la commande que tu vas taper 50 fois par jour
  • Les noms de services servent de hostnames dans le réseau interne

Navigation : Precedent : 08 - Images de base | Suivant : 10 - Compose avance


Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.