Docker Compose est l'outil qui permet de définir plusieurs conteneurs dans un seul fichier YAML et de les lancer tous d'une seule commande. Une véritable application se résume rarement à un seul processus : un serveur web, une base de données et, le plus souvent, une couche de cache fonctionnent ensemble. Les démarrer un par un avec docker run est à la fois fastidieux et source d'erreurs. Dans cet article, nous construirons de zéro une pile typique composée des services web, PostgreSQL et Redis, en abordant la communication entre services, les données persistantes et les variables d'environnement à travers des exemples concrets.
Quel problème résout Docker Compose ?
Lancer un seul conteneur est simple, mais dans les vrais projets les choses se compliquent vite. Chaque service a sa propre image, son port, son réseau et ses variables d'environnement — et ils doivent souvent démarrer dans un ordre précis. Compose déplace cette complexité dans un fichier déclaratif :
- Source unique : toute la pile vit dans
compose.yaml; un collègue clone le dépôt et tape simplementdocker compose up. - Réseau automatique : Compose crée un réseau partagé pour vos services, et les conteneurs se joignent par leur nom de service.
- Reproductibilité : le même fichier produit la même pile sur la machine d'un développeur comme en CI.
Remarque : dans Docker moderne, la commande est docker compose (avec une espace) ; l'ancien binaire docker-compose (avec un tiret) fonctionne encore mais a été remplacé par Compose V2.
Votre premier fichier compose.yaml
Créez un dossier et ajoutez-y un compose.yaml. Commençons par un simple service web et une base de données :
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Quelques détails importants : l'entrée "8080:80" sous ports relie le port 8080 de l'hôte au port 80 du conteneur. depends_on fait démarrer le service web après db (sans toutefois garantir que db soit réellement prête — nous y reviendrons). Le bloc volumes crée un volume persistant qui conserve les fichiers de la base même si le conteneur est supprimé.
Ajouter une couche de cache : Redis
La plupart des applications utilisent Redis pour les sessions, les files d'attente ou le cache. Ajouter un troisième service tient à un bloc supplémentaire :
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
depends_on:
- db
- cache
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- db-data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
command: ["redis-server", "--save", "60", "1"]
volumes:
db-data:
Voici le point agréable : depuis le conteneur web, vous atteignez la base via le nom d'hôte db et Redis via cache. Le DNS interne mis en place par Compose résout automatiquement le nom de service vers la bonne IP. Ainsi, dans la configuration de votre application, les chaînes de connexion deviennent postgres://app:secret@db:5432/appdb et redis://cache:6379 — aucune IP codée en dur n'est nécessaire.
Variables d'environnement et fichier .env
Coder en dur les mots de passe dans le YAML est une mauvaise idée. Compose lit automatiquement un fichier .env voisin et substitue les variables avec la syntaxe ${...} :
# .env
POSTGRES_PASSWORD=une-valeur-tres-secrete
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: appdb
Ajoutez .env à votre .gitignore pour que les secrets ne se retrouvent jamais dans le dépôt. Laisser un exemple .env.example pour le reste de l'équipe est une bonne habitude.
Une vraie disponibilité avec les health checks
depends_on ne contrôle que l'ordre de démarrage ; il ne garantit pas que la base accepte les connexions. Le service web peut tenter de se connecter alors que db démarre encore, et échouer. La solution consiste à définir un healthcheck et à combiner depends_on avec condition: service_healthy :
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: appdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 3s
retries: 5
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
depends_on:
db:
condition: service_healthy
Désormais, le conteneur web ne démarre qu'après le succès de la commande pg_isready. Cela élimine la plupart des erreurs du type « la base n'est pas encore prête ».
Au quotidien : les commandes essentielles
Voici les commandes que vous utiliserez le plus souvent pour lancer et gérer la pile :
docker compose up -d— démarre tous les services en arrière-plan.docker compose ps— liste les services en cours et leur état.docker compose logs -f web— suit en direct les logs d'un service précis.docker compose exec db psql -U app appdb— exécute une commande dans le conteneur db en cours.docker compose down— arrête et supprime les services. Ajoutez-vpour supprimer aussi les volumes.
Si vous avez modifié une image (par exemple, vous construisez votre propre Dockerfile), reconstruisez avec docker compose up -d --build.
Questions fréquentes
Quelle est la différence entre docker-compose et docker compose ?
docker-compose (avec tiret) est l'ancien outil V1 écrit en Python. docker compose (avec espace) est le plugin V2 basé sur Go, intégré au CLI Docker. Sur les installations actuelles, il faut utiliser la version avec espace ; la syntaxe YAML est en grande partie identique.
Mes données seront-elles perdues quand le conteneur est supprimé ?
Non — les volumes nommés définis sous volumes sont indépendants du cycle de vie du conteneur. docker compose down supprime les conteneurs, mais le volume reste ; vos données sont toujours là au prochain up. Seul down -v supprime aussi les volumes.
Compose convient-il à la production ?
Il convient parfaitement aux petites et moyennes configurations sur un seul serveur. Pour des systèmes multi-nœuds, à mise à l'échelle automatique et auto-réparants, un orchestrateur comme Kubernetes est un meilleur choix. Pensez à Compose pour le développement et les scénarios de production simples, et à Kubernetes pour la grande échelle.
Vous souhaitez regrouper votre pile dans un seul fichier ? Pour simplifier votre développement et votre déploiement avec Docker Compose, contactez-moi — planifions ensemble l'infrastructure de votre projet.