3.1 · Le fichier compose.yml : services, ports, volumes

Niveau 3 · Docker Compose

3.1Le fichier compose.yml : services, ports, volumes

Objectif : décrire une application complète (web + base) dans un compose.yml lisible.
Temps estimé : 14 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

L'essentiel en 30 secondes

  • Déclarer l'état voulu, pas les ordres : chaque service a son image (ou build), ses ports, ses variables, ses volumes et son réseau — Compose crée tout depuis ce fichier versionné.
  • Un service = image + ports + env + volumes : ports entre guillemets ("8080:80"), volumes et réseaux déclarés en bas et créés automatiquement, depends_on pour l'ordre de démarrage.
  • YAML : l'indentation est la loi : espaces, jamais de tabulations, deux espaces par niveau — docker compose config valide et affiche le fichier résolu avant tout lancement.

Mini-cas filé — Idir remplace ses lignes de 200 caractères

Idir, devops junior à Alger, lance la maquette de son équipe avec deux lignes docker run de 200 caractères recopiées d'un pense-bête — un port oublié, et la démo rate. Il écrit un compose.yml de 25 lignes (web + base, volume nommé, depends_on), le valide avec docker compose config, le committe : désormais, un seul fichier fait foi et toute l'équipe démarre la même application. Fini la doc « comment lancer » récitée de mémoire.

Ce même cas revient dans le cours, le schéma, le script et le défi 48h.

1. Déclarer au lieu d'ordonner : le fichier qui fait foi

Compose remplace vos docker run par un fichier versionné : on y décrit l'ÉTAT VOULU de l'application (quels services, quels ports, quels volumes, quels réseaux) et Compose crée tout — réseaux, volumes, conteneurs dans l'ordre. Fini les lignes de 200 caractères recopiées de mémoire : le compose.yml est commité, relu comme du code, et constitue le lanceur officiel de l'appli. C'est le passage du geste manuel au déclaratif.

Chaque service (web, bdd, cache…) déclare son image (ou son build local), ses ports ("8080:80", guillemets obligatoires en YAML), son environment, ses volumes (pgdata:/var/lib/postgresql/data) et son réseau. depends_on fixe l'ordre de démarrage entre services. Les volumes et réseaux se déclarent en bas du fichier : Compose les crée automatiquement au premier up.

2. YAML : l'indentation est la loi, config est le juge

Compose parle YAML : espaces et jamais de tabulations, deux espaces par niveau, « : » suivi d'une espace. La quasi-totalité des erreurs Compose vient de là : une indentation cassée, des ports sans guillemets (8080:80 lu comme un nombre sexagésimal !), un « : » sans espace. Écrire lentement, indenter proprement : c'est 80 % du travail.

Le réflexe avant chaque lancement : docker compose config. Cette commande valide le fichier et affiche le compose RÉSOLU — ou l'erreur exacte avec sa ligne. Idir ne lance plus jamais un up sur un fichier non validé : config d'abord, up ensuite. Un fichier par appli, commité, validé : reproductible partout.

Erreur d'interprétation fréquente : « depends_on attend que la base soit prête, et les ports peuvent s'écrire sans guillemets ». Non, deux fois. depends_on ORDONNE le démarrage sans attendre la disponibilité — la robustesse vient des healthchecks et des retries (niveau 4). Et 8080:80 sans guillemets est lu comme un nombre sexagésimal par YAML : les ports se quotent toujours. Ordonner n'est pas attendre, et quoter n'est pas décoratif.
Décrire l'appli au lieu d'ordonner Services, volumes, réseaux, validation ServicesImage + ports quotés + env + volumes + depends_on+Volumes + réseauxDéclarés en bas, créés automatiquement+docker compose configValide et affiche le résolu avant up Un fichier versionné décrit tout : reproductible partout.
Services, volumes, réseaux, validation
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Services : Idir déclare web (image, ports quotés) et bdd (image, mot de passe en variable, volume) au lieu de deux lignes run. 2) Socle : volumes et réseaux déclarés en bas, créés automatiquement au premier up. 3) Validation : docker compose config affiche le fichier résolu ou l'erreur exacte avant tout lancement. Leçon : on déclare l'état voulu, Compose exécute — le fichier commité remplace la doc.

🔎 Exemple concret — Web + base en 25 lignes, validé avant lancement

Idir écrit son premier stack web + base, mot de passe en variable.

services:
  web:
    image: nginx:1.27
    ports: ["8080:80"]
    depends_on: [bdd]
    networks: [front]
  bdd:
    image: postgres:16.4
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes: [pgdata:/var/lib/postgresql/data]
    networks: [front]
volumes:
  pgdata:
networks:
  front:
# Puis : docker compose config (valider), mot de passe dans .env non commité.

Lecture : deux services, un volume persistant, un réseau, un ordre de démarrage.

Leçon : ce fichier commité remplace toute la doc « comment lancer ».

Vocabulaire de la section

Service
Un conteneur décrit dans Compose (web, bdd, cache) : image ou build, ports, variables, volumes, réseau.

Exemple simple : Le service web d'Idir (nginx, port 8080 publié).

Ce que ce n'est pas : une ligne docker run recopiée de mémoire.

Réflexe : un rôle applicatif = un service déclaré.

depends_on
L'ordre de démarrage entre services : lance la base avant le web, sans attendre qu'elle soit prête.

Exemple simple : web depends_on bdd : la base démarre en premier.

Ce que ce n'est pas : une garantie que la base est disponible.

Réflexe : ordonner avec depends_on, fiabiliser avec healthcheck + retry.

Volume Compose
Volume nommé déclaré en bas du fichier et créé automatiquement : la persistance des données.

Exemple simple : pgdata monté sur /var/lib/postgresql/data.

Ce que ce n'est pas : des données prisonnières d'un conteneur éphémère.

Réflexe : toute donnée à garder = volume nommé.

config
Commande qui valide le compose et affiche le fichier résolu — ou l'erreur exacte.

Exemple simple : Idir passe config avant chaque up.

Ce que ce n'est pas : un up à l'aveugle sur un YAML cassé.

Réflexe : config d'abord, up ensuite, toujours.

YAML
Le format indenté du compose.yml : espaces (jamais de tabulations), « : » + espace, ports entre guillemets.

Exemple simple : "8080:80" quoté, deux espaces par niveau.

Ce que ce n'est pas : des tabulations et des ports non quotés.

Réflexe : espaces, deux par niveau, guillemets sur les ports.

En pratique — Écrire votre premier stack

  1. Créez un dossier avec le compose.yml web + bdd ci-dessus (mot de passe en ${POSTGRES_PASSWORD}, .env local non commité).
  2. Validez-le avec docker compose config : lisez le fichier résolu affiché.
  3. Corrigez jusqu'à zéro erreur (indentation, guillemets des ports, « : » + espace).
  4. Committez le fichier : c'est désormais votre lanceur officiel, relu comme du code.
Votre application se décrit en un fichier versionné et validé : reproductible par toute l'équipe.

Script prêt à dire — présenter le compose à l'équipe (30 s)

« Fini les lignes run de 200 caractères : un seul compose.yml décrit web + base — ports, volume, ordre de démarrage — validé par config et commité. Chacun démarre exactement la même application, sans pense-bête. »

À dire en point d'équipe ; projeter le config résolu.

Modèle copier-coller — stack web + base valide

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
    depends_on:
      - bdd
    networks:
      - front
  bdd:
    image: postgres:16.4
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - front

volumes:
  pgdata:

networks:
  front:
# .env local (NON commité) : POSTGRES_PASSWORD=

Indépendant

Un compose.yml validé par config et votre démo démarre partout à l'identique.

PME à Alger

Idir committe le stack web + base : l'équipe démarre la même maquette sans pense-bête.

Équipe projet

Imposer config vert + commit du compose avant toute démo partagée.

Débutant

Cette semaine : un stack web + base validé au bouton config, puis commité.

Prudence : Mot de passe de base via le .env local, jamais en dur dans le compose commité : ${POSTGRES_PASSWORD} dans le fichier, valeur réelle uniquement dans le .env (non versionné, fourni via un .env.example).

✓ Bonnes pratiques

  • Mettez les ports entre guillemets en YAML ("8080:80"), systématiquement.
  • Passez docker compose config avant chaque up, et lisez le résolu.
  • Un fichier par appli, commité et relu comme du code.

✗ Pièges fréquents

  • Tabulations dans le YAML : espaces uniquement, deux par niveau.
  • Ports sans guillemets (8080:80 devient un nombre sexagésimal).
  • Croire que depends_on attend que la base soit prête (il ne fait qu'ordonner).

Points clés à retenir

  • Compose DÉCRIT l'état voulu, Docker exécute : le fichier versionné remplace les lignes run.
  • SERVICE = image (ou build) + ports quotés + env + volumes + depends_on pour l'ordre.
  • YAML : espaces, jamais de tabulations, « : » + espace — 80 % des erreurs viennent de là.
  • VOLUMES et RÉSEAUX déclarés en bas, créés automatiquement ; config valide avant up.

Défi 48h — appliquez demain

Remplacez 1 lancement manuel par un compose.yml validé (config) et commité, avec le mot de passe en variable.

Checklist sortie de section
  • Mon appli se décrit en un fichier versionné.
  • Mes ports sont quotés et mon YAML sans tabulations.
  • Mon config est vert avant chaque up.
Auto-évaluation 1-5 : quelqu'un d'autre démarre-t-il mon appli sans me poser de question ?est-ce que chaque mot de passe est hors du fichier commité ?

Questions fréquentes

depends_on attend-il que la base soit prête ?

NON : depends_on ORDONNE le démarrage (la base démarre avant le web) sans attendre sa disponibilité. Si le web se connecte trop tôt, il échoue : la robustesse vient des healthchecks et des retries applicatifs (niveau 4.2). Retenez : ordonner ≠ attendre. Pour une maquette simple, relancer le web suffit ; pour un vrai stack, boucle de reconnexion au démarrage côté application.

Faut-il versionner le compose.yml, et où mettre les secrets ?

OUI, toujours : le compose.yml est le lanceur officiel de l'appli, relu comme du code et commité. Les SECRETS n'y figurent jamais en dur : utilisez des variables (${POSTGRES_PASSWORD}) alimentées par un .env local non commité (ou un secret managé en production), et versionnez un .env.example avec des valeurs factices pour documenter les clés attendues.

Vérifiez votre compréhension

Que valide « docker compose config » avant tout lancement ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 3Questions inédites et durcies pour valider vos acquis