Docker Compose déploie une application multi-conteneurs en une seule commande, à partir d'un fichier compose.yaml qui décrit toute votre architecture. Au terme de ce guide, vous saurez écrire ce fichier, faire communiquer vos services (application web + base de données), persister vos données avec des volumes, gérer vos secrets, itérer en direct avec watch, et épingler puis scanner vos images.
Le guide s'adresse aux débutants comme aux développeurs ayant déjà manipulé Docker. Prérequis : Docker installé. Résultat concret : une stack WordPress + MySQL fonctionnelle en 15 minutes, que vous pourrez adapter à vos propres projets. Toutes les commandes sont testées sur Docker Compose v5.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Architecture services/réseaux/volumes : comprendre les 3 concepts fondamentaux de Docker Compose et comment ils interagissent.
- Écrire un compose.yaml multi-services : créer une stack WordPress + MySQL avec dépendances, volumes et variables.
- Orchestrer en CLI : maîtriser
up,down,logs,exec,config,watchetscale. - Fiabiliser le démarrage : healthchecks,
depends_on, init containerspre_start. - Épingler et scanner : figer chaque image par digest et la passer à Trivy et Grype.
- Connaître les limites : identifier quand migrer vers Docker Swarm ou Kubernetes.
Prérequis
Section intitulée « Prérequis »Qu'est-ce que Docker Compose ?
Section intitulée « Qu'est-ce que Docker Compose ? »Docker Compose est un outil qui permet de définir et lancer plusieurs conteneurs Docker en une seule commande. Au lieu d'exécuter plusieurs docker run avec des options complexes, vous décrivez votre architecture dans un fichier YAML et lancez tout avec docker compose up.
Analogie : imaginez un chef d'orchestre. Chaque musicien (conteneur) joue sa partition, mais c'est le chef (Compose) qui coordonne l'ensemble : qui démarre quand, qui communique avec qui, où sont stockées les partitions (données).
Avec vs sans Docker Compose
Section intitulée « Avec vs sans Docker Compose »Pour mieux comprendre l'intérêt de Docker Compose, comparons deux approches pour déployer la même application (WordPress + MySQL).
Sans Docker Compose, vous exécutez manuellement chaque commande, dans le bon ordre, en vous souvenant de toutes les options. Si vous faites une erreur, vous recommencez. Et si un collègue veut reproduire votre environnement, vous devez lui transmettre toutes ces commandes.
Avec Docker Compose, tout est décrit dans un fichier versionnable. N'importe qui peut cloner votre repo et lancer docker compose up pour obtenir exactement le même environnement.
| Sans Compose | Avec Compose |
|---|---|
docker network create mynet | Un seul fichier compose.yaml |
docker run -d --name db --network mynet -e MYSQL_ROOT_PASSWORD=secret mysql | Une seule commande docker compose up |
docker run -d --name wp --network mynet -e WORDPRESS_DB_HOST=db -p 8080:80 wordpress | Tout est versionné et reproductible |
| 3 commandes à retenir et exécuter dans l'ordre | Architecture documentée dans le code |
Quand utiliser Docker Compose ?
Section intitulée « Quand utiliser Docker Compose ? »Docker Compose excelle quand vous contrôlez une seule machine et que la haute disponibilité n'est pas critique. C'est l'outil idéal pour reproduire un environnement de production localement, ou pour des environnements de test isolés.
En revanche, dès que vous devez répartir la charge sur plusieurs serveurs, gérer des pannes automatiquement, ou déployer avec zéro downtime, Compose montre ses limites. Dans ces cas, tournez-vous vers Kubernetes ou Docker Swarm.
| ✅ Utilisez Compose pour | ❌ N'utilisez pas Compose pour |
|---|---|
| Développement local multi-services | Production haute disponibilité |
| Tests d'intégration | Déploiement sur plusieurs serveurs |
| Démos et POC | Scaling automatique |
| CI/CD (environnements de test) | Orchestration complexe (Kubernetes) |
Installation (si nécessaire)
Section intitulée « Installation (si nécessaire) »Vérifiez que Docker est installé et que Compose est disponible :
docker --versiondocker compose versionRésultat attendu : deux numéros de version s'affichent. La commande docker compose version doit afficher Docker Compose version v5.x.x ou plus récent.
Si docker compose version échoue, installez le plugin :
# Ubuntu/Debiansudo apt updatesudo apt install docker-compose-plugin
# Vérificationdocker compose versionConcepts clés
Section intitulée « Concepts clés »Avant d'écrire votre premier fichier, comprenez ces trois concepts fondamentaux.
Services
Section intitulée « Services »Un service représente un conteneur avec toute sa configuration. C'est l'unité de base dans Docker Compose. Dans notre exemple, nous aurons deux services : wordpress (l'application web) et mysql (la base de données).
Pensez à un service comme une recette pour créer un conteneur. Cette recette spécifie quelle image utiliser, quelles variables d'environnement injecter, quels ports ouvrir. Quand vous lancez docker compose up, Compose lit ces recettes et crée les conteneurs correspondants.
Chaque service peut définir :
- L'image Docker à utiliser (depuis Docker Hub ou un registre privé)
- Les ports à exposer vers l'extérieur ou entre services
- Les variables d'environnement pour configurer l'application
- Les volumes à monter pour persister ou partager des données
- Les dépendances vers d'autres services (qui doit démarrer en premier)
- Les ressources (limites CPU, mémoire) et les politiques de redémarrage
Un réseau Docker est un espace de communication isolé où les conteneurs échangent des données. C'est comme un réseau local virtuel : les conteneurs connectés au même réseau peuvent se voir, ceux sur des réseaux différents sont isolés.
La force de Docker Compose, c'est la résolution DNS automatique. Dans un réseau Compose, chaque service est accessible par son nom. Le service wordpress contacte la base de données en utilisant mysql comme nom d'hôte, sans connaître son adresse IP.
Docker Compose crée automatiquement un réseau par défaut nommé <dossier>_default. Tous les services y sont connectés et communiquent sans configuration supplémentaire. Vous pouvez aussi créer des réseaux personnalisés pour isoler certains services (séparer le frontend du backend).
Les conteneurs sont éphémères par nature : quand vous supprimez un conteneur, tout ce qu'il contenait disparaît. C'est problématique pour une base de données, vous ne voulez pas perdre vos données à chaque redémarrage.
Un volume résout ce problème en stockant les données en dehors du conteneur, sur le système de fichiers de l'hôte. Même si le conteneur est supprimé et recréé, les données du volume sont préservées.
Docker propose trois types de stockage, chacun adapté à un usage :
| Type | Usage | Exemple |
|---|---|---|
| Volume nommé | Données persistantes (BDD, fichiers) | db_data:/var/lib/mysql |
| Bind mount | Code source en développement | ./src:/app |
| tmpfs | Données temporaires en RAM | tmpfs:/tmp |
Votre premier compose.yaml
Section intitulée « Votre premier compose.yaml »Pour illustrer ces concepts, nous allons déployer une stack simple : WordPress + MySQL. Le nom de fichier moderne est compose.yaml ; docker-compose.yml reste reconnu.
Création de la structure du projet
Section intitulée « Création de la structure du projet »-
Créez un dossier pour votre projet
Fenêtre de terminal mkdir ~/mon-wordpress && cd ~/mon-wordpress -
Créez le fichier
compose.yamlFenêtre de terminal touch compose.yaml -
Ajoutez la configuration suivante
services:wordpress:image: wordpress@sha256:b2ceeaabb8fa90e12f32fdf5c2479f4cef4508255fb406bd19aa23b1ce59bc46 # WordPress 7.0ports:- "8080:80"environment:WORDPRESS_DB_HOST: mysqlWORDPRESS_DB_USER: wordpressWORDPRESS_DB_PASSWORD: wordpress_passwordWORDPRESS_DB_NAME: wordpressdepends_on:- mysqlrestart: unless-stoppedmysql:image: mysql:8.0@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b # MySQL 8.0.46environment:MYSQL_DATABASE: wordpressMYSQL_USER: wordpressMYSQL_PASSWORD: wordpress_passwordMYSQL_ROOT_PASSWORD: root_secret_passwordvolumes:- db_data:/var/lib/mysqlrestart: unless-stoppedvolumes:db_data:Explications :
services:, définit les conteneurs à créer.image: ...@sha256:..., l'image officielle épinglée par digest.ports: "8080:80", expose le port 80 du conteneur sur le port 8080 de la machine.WORDPRESS_DB_HOST: mysql, WordPress contacte MySQL via son nom de service.depends_on:, WordPress attend que MySQL démarre (mais pas qu'il soit prêt).volumes: db_data:/var/lib/mysql, les données MySQL sont persistées.restart: unless-stopped, redémarre automatiquement sauf arrêt manuel.
Lancement de la stack
Section intitulée « Lancement de la stack »Quand vous exécutez docker compose up, Compose orchestre la création de l'infrastructure. Voici ce qui se passe en coulisses.
-
Lancez la stack
Fenêtre de terminal docker compose up -dL'option
-d(detached) lance les conteneurs en arrière-plan.Résultat attendu :
[+] Running 3/3✔ Network mon-wordpress_default Created✔ Container mon-wordpress-mysql-1 Started✔ Container mon-wordpress-wordpress-1 Started -
Vérifiez que les conteneurs tournent
Fenêtre de terminal docker compose psRésultat attendu (le format par défaut en v5 est large) :
NAME IMAGE SERVICE STATUS PORTSmon-wordpress-mysql-1 mysql:8.0 mysql Up 8 seconds 3306/tcp, 33060/tcpmon-wordpress-wordpress-1 wordpress wordpress Up 8 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcpLe mapping de port apparaît maintenant en IPv4 et IPv6. Pour un affichage compact, utilisez
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}". -
Testez l'application
Ouvrez votre navigateur à l'adresse http://localhost:8080. Vous devriez voir l'écran d'installation de WordPress.
-
Consultez les logs si besoin
Fenêtre de terminal docker compose logs# Ou pour un service précis :docker compose logs mysql
Configuration avancée
Section intitulée « Configuration avancée »Variables d'environnement avec fichier .env
Section intitulée « Variables d'environnement avec fichier .env »Mettre des mots de passe en clair dans compose.yaml pose deux problèmes : c'est un risque de sécurité si vous versionnez le fichier (les secrets se retrouvent dans l'historique Git), et c'est peu pratique quand vous avez des environnements différents (dev, staging, prod).
La solution : externaliser vos variables dans un fichier .env. Docker Compose lit automatiquement ce fichier s'il existe dans le même dossier, et remplace les variables ${...} par leurs valeurs.
# Fichier .env (même dossier que compose.yaml)MYSQL_ROOT_PASSWORD=super_secret_rootMYSQL_PASSWORD=wordpress_passwordWORDPRESS_DB_PASSWORD=wordpress_passwordPuis référencez-les dans votre Compose :
services: mysql: image: mysql:8.0@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b # MySQL 8.0.46 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_PASSWORD: ${MYSQL_PASSWORD}Vérifiez la substitution avant de démarrer avec docker compose config, qui affiche la configuration finale résolue.
Gestion des secrets (production)
Section intitulée « Gestion des secrets (production) »Les fichiers .env sont pratiques, mais les variables d'environnement sont visibles dans les logs, les processus et via docker inspect. Pour des secrets vraiment sensibles, Docker propose un mécanisme plus sûr : les secrets.
Le contenu sensible est stocké dans un fichier séparé et monté en lecture seule dans le conteneur, à l'emplacement /run/secrets/<nom>. L'application lit le fichier au lieu d'une variable d'environnement. Le secret n'apparaît jamais dans l'environnement ni dans les logs.
services: mysql: image: mysql:8.0@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b # MySQL 8.0.46 environment: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password secrets: - mysql_root_password
secrets: mysql_root_password: file: ./secrets/mysql_root_password.txtLe mot de passe est lu depuis le fichier monté, jamais exposé dans l'environnement.
Dépendances et healthchecks
Section intitulée « Dépendances et healthchecks »Vous avez remarqué le depends_on dans notre configuration WordPress. Cette directive garantit que MySQL démarre avant WordPress. Mais attention : démarré ne signifie pas prêt.
Docker considère MySQL comme démarré dès que le processus est lancé. Or MySQL a besoin de quelques secondes pour initialiser ses bases et ouvrir son port. Si WordPress se connecte pendant cette initialisation, il échoue avec « Error establishing database connection ».
La solution : les healthchecks. Un healthcheck est une commande que Docker exécute régulièrement pour vérifier si le service est vraiment opérationnel. Avec condition: service_healthy, le service dépendant attend que le healthcheck soit positif.
services: mysql: image: mysql:8.0@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b # MySQL 8.0.46 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5
wordpress: image: wordpress@sha256:b2ceeaabb8fa90e12f32fdf5c2479f4cef4508255fb406bd19aa23b1ce59bc46 # WordPress 7.0 depends_on: mysql: condition: service_healthyAu démarrage, la séquence observée est nette : mysql Started puis mysql Waiting puis mysql Healthy, et seulement ensuite wordpress Started. WordPress ne démarre qu'une fois MySQL réellement prêt.
Init containers et hooks de cycle de vie
Section intitulée « Init containers et hooks de cycle de vie »Compose v5.3 a introduit les init containers natifs avec le champ pre_start : un conteneur éphémère qui s'exécute après la création du conteneur de service mais avant son démarrage. C'est l'endroit idéal pour une migration de base de données, préparer un volume ou fixer des permissions, sans polluer l'image applicative.
services: web: image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa # nginx 1.31.2 ports: - "8080:80" pre_start: - command: sh -c "echo 'page initialisée par le pre_start' > /usr/share/nginx/html/index.html" volumes: - web_root:/usr/share/nginx/html
volumes: web_root:L'init container partage les volumes du service : ici il écrit dans web_root, et nginx sert ensuite cette page. Vous pouvez aussi lui donner sa propre image: (par exemple image: busybox), à condition qu'elle soit disponible localement, sinon le démarrage échoue avec No such image.
Deux hooks complètent le cycle de vie : post_start (après le démarrage du conteneur) et pre_stop (avant son arrêt, ignoré si le conteneur s'arrête de lui-même).
services: app: image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa # nginx 1.31.2 post_start: - command: sh -c "echo prêt > /tmp/ready" pre_stop: - command: ./drain.shBuild d'images personnalisées
Section intitulée « Build d'images personnalisées »Jusqu'ici nous avons utilisé des images publiques. Dans un projet réel, vous aurez souvent votre propre code à conteneuriser. Plutôt que de builder manuellement avec docker build, demandez à Compose de le faire.
La directive build remplace image et indique où trouver le Dockerfile :
services: api: build: context: ./backend # Dossier contenant le code et le Dockerfile dockerfile: Dockerfile # Optionnel si nom par défaut ports: - "3000:3000"Avec docker compose up --build, Compose construit l'image puis lance le conteneur. En v5, cette construction est déléguée à Docker Bake : la sortie mentionne load local bake definitions. Le comportement reste identique à docker build, avec le cache et les fonctionnalités de BuildKit.
Développement en direct avec watch
Section intitulée « Développement en direct avec watch »Recompiler à la main à chaque changement de code casse le rythme. docker compose watch surveille vos fichiers et synchronise ou reconstruit automatiquement le conteneur. C'est le remplaçant moderne du cycle « modifier, --build, relancer ».
services: web: image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa # nginx 1.31.2 ports: - "8080:80" develop: watch: - action: sync path: ./app target: /usr/share/nginx/htmlLancez la stack puis la surveillance :
docker compose up -ddocker compose watchModifiez un fichier de ./app : il est synchronisé en direct dans le conteneur, sans rebuild. Trois actions existent : sync (copie le fichier), rebuild (reconstruit l'image, pour un changement de dépendances) et sync+restart (synchronise puis redémarre le service, pour un fichier de configuration).
Scaling et réplication
Section intitulée « Scaling et réplication »Docker Compose peut scaler horizontalement un service en créant plusieurs réplicas identiques. C'est utile pour répartir la charge ou simuler un environnement distribué.
# Lancer 3 instances du service webdocker compose up -d --scale web=3docker compose psAvec un port fixe, cette commande échoue : Docker ne peut pas mapper plusieurs conteneurs sur le même port hôte.
Error response from daemon: ... Bind for 0.0.0.0:8080 failed: port is already allocatedLa solution est une plage de ports, qui attribue un port distinct à chaque réplica :
services: web: image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa # nginx 1.31.2 ports: - "8080-8082:80"NAME PORTSprojet-web-1 0.0.0.0:8080->80/tcp, [::]:8080->80/tcpprojet-web-2 0.0.0.0:8081->80/tcp, [::]:8081->80/tcpprojet-web-3 0.0.0.0:8082->80/tcp, [::]:8082->80/tcpVous pouvez aussi fixer le nombre de réplicas dans le fichier avec deploy.replicas. Contrairement à ce qu'on lit parfois, ce champ n'est plus réservé à Swarm : docker compose up l'honore et crée bien le nombre demandé de conteneurs.
services: web: image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa # nginx 1.31.2 deploy: replicas: 3Limites du scaling avec Compose : pas de load balancer intégré (il faut un reverse proxy), pas de répartition intelligente, pas de scaling selon la charge. Pour ces besoins, passez à Docker Swarm ou Kubernetes.
Restart policies (politiques de redémarrage)
Section intitulée « Restart policies (politiques de redémarrage) »Les restart policies définissent le comportement d'un conteneur en cas d'arrêt (crash, arrêt manuel, reboot serveur). C'est crucial pour la résilience.
| Politique | Comportement | Usage recommandé |
|---|---|---|
no | Ne jamais redémarrer (par défaut) | Jobs batch, tâches ponctuelles |
always | Redémarre toujours, même après arrêt manuel ou reboot | Services critiques (BDD, API) |
unless-stopped | Redémarre sauf si arrêté manuellement | Services persistants en production |
on-failure | Redémarre uniquement en cas de crash (exit code ≠ 0) | Services instables, diagnostics |
services: db: image: postgres:16-alpine@sha256:23e88eb049fd5d54894d70100df61d38a49ed97909263f79d4ff4c30a5d5fca2 # PostgreSQL 16.11 restart: always # BDD toujours disponible worker: image: mon-worker:1.4.0 # votre image, épinglée par tag ou digest restart: on-failure # redémarre uniquement en cas de crashVérifiez le compteur de redémarrages avec docker inspect <conteneur> | grep -A 5 RestartCount.
Profils : services optionnels
Section intitulée « Profils : services optionnels »Les profils définissent des services optionnels qui ne démarrent que si explicitement demandés. Parfait pour les outils de debug (pgadmin, adminer), les services de développement, ou les mocks de test.
services: db: image: postgres:16-alpine@sha256:23e88eb049fd5d54894d70100df61d38a49ed97909263f79d4ff4c30a5d5fca2 # PostgreSQL 16.11 # Toujours démarré (pas de profil) pgadmin: image: dpage/pgadmin4:9.7 # épinglez par digest en production profiles: ["debug"] # démarré uniquement avec --profile debug ports: - "5050:80"# Démarrage normal : db uniquementdocker compose up -d
# Démarrage avec pgadmin pour debugdocker compose --profile debug up -dSans profil, seul db démarre ; avec --profile debug, db et pgadmin démarrent. On combine plusieurs profils en répétant l'option (--profile debug --profile monitoring).
Multi-fichiers et environnements
Section intitulée « Multi-fichiers et environnements »Dans un projet réel, vous avez souvent des configurations différentes selon l'environnement. Docker Compose fusionne plusieurs fichiers YAML, plus maintenable que de tout dupliquer.
# Développement : base + override (auto-chargé)docker compose up -d
# Production : base + prod (ignore override)docker compose -f compose.yaml -f compose.prod.yml up -dChaque fichier écrase les propriétés du précédent : l'ordre des -f est important, le fichier de base d'abord. Les scalaires (image, restart) sont écrasés, les listes (ports, volumes) fusionnées. Vérifiez le résultat final avec docker compose config.
Épingler et scanner les images
Section intitulée « Épingler et scanner les images »Une image tirée par tag mouvant (:latest, :8) peut changer sous vos pieds : le même fichier Compose déploie une image différente d'un jour à l'autre. Pire, une image compromise ou vulnérable passe inaperçue. Deux réflexes règlent cela : épingler par digest et scanner.
Épingler par digest
Section intitulée « Épingler par digest »Le digest (@sha256:...) identifie le contenu exact d'une image, de façon immuable. Récupérez-le après un docker pull :
docker pull nginx:alpinedocker inspect --format '{{index .RepoDigests 0}}' nginx:alpine# nginx@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefaReportez ce digest dans le fichier, en gardant le tag en commentaire pour la lisibilité :
services: web: image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa # nginx 1.31.2Vous tirez désormais toujours la même image, quel que soit le déplacement du tag. Pour automatiser les mises à jour de ces digests, un outil comme Renovate ouvre des pull requests quand une nouvelle version paraît.
Scanner avec Trivy et Grype
Section intitulée « Scanner avec Trivy et Grype »Épingler fige l'image, mais ne dit rien de ses vulnérabilités. Deux scanners de référence répondent à cette question. Trivy donne un résumé par sévérité :
trivy image mysql:8.0# mysql:8.0 (oracle 9.7)# Total: 80 (UNKNOWN: 0, LOW: 2, MEDIUM: 32, HIGH: 46, CRITICAL: 0)Le contraste avec une image minimale est frappant : la même commande sur nginx:alpine renvoie 0 vulnérabilité. La première leçon de sécurité tient là : une image slim (Alpine, distroless) réduit drastiquement la surface d'attaque.
Grype apporte un second regard, avec un score EPSS (probabilité d'exploitation) et un score de risque :
grype nginx:alpine# NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK# tiff 4.7.1-r0 apk CVE-2023-52356 High 2.2% (80th) 1.6# curl 8.19.0-r0 apk CVE-2026-5773 High 0.5% (41st) 0.4Détail instructif : sur nginx:alpine, Grype signale des CVE (tiff, curl) que Trivy compte à zéro. Ce n'est pas un bug, c'est la réalité de deux bases de vulnérabilités et de deux logiques de correspondance différentes. La conclusion pratique : ne dépendez pas d'un seul scanner, croisez-les, et intéressez-vous aux failles corrigées (FIXED IN renseigné) que vous pouvez éliminer par une mise à jour.
Les deux outils scannent aussi par digest, exactement ce que vous avez épinglé :
trivy image nginx@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefagrype nginx@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefaEn CI, faites échouer le pipeline sur les vulnérabilités critiques (trivy image --exit-code 1 --severity CRITICAL <image>) pour ne jamais déployer une image trouée.
Commandes essentielles
Section intitulée « Commandes essentielles »Voici les commandes du quotidien. La plupart s'exécutent depuis le dossier contenant votre compose.yaml.
| Commande | Description |
|---|---|
docker compose up -d | Démarre tous les services en arrière-plan |
docker compose down | Arrête et supprime conteneurs et réseaux |
docker compose down -v | Idem + supprime les volumes (⚠️ perte de données) |
docker compose ps | Liste les conteneurs du projet |
docker compose ps --format json | Sortie JSON Lines (un objet par ligne), pour le scripting |
docker compose logs -f | Affiche les logs en temps réel |
docker compose exec mysql bash | Ouvre un shell dans le conteneur MySQL |
docker compose watch | Synchronise le code en direct pendant le développement |
docker compose restart | Redémarre tous les services |
docker compose pull | Met à jour les images |
docker compose config | Valide et affiche la configuration finale |
Dépannage
Section intitulée « Dépannage »Votre premier réflexe face à un problème : consulter les logs avec docker compose logs, ils contiennent souvent la réponse.
| Symptôme | Cause probable | Solution |
|---|---|---|
port is already allocated | Un autre service utilise déjà le port | Changez le port dans ports: ou arrêtez l'autre service |
| "Error establishing database connection" | La BDD n'est pas encore prête | Ajoutez un healthcheck + condition: service_healthy |
Les données disparaissent après down | Vous avez utilisé down -v qui supprime les volumes | Utilisez down sans -v |
network not found | Le réseau a été supprimé manuellement | Relancez docker compose up |
| Conteneur en restart loop | L'application plante au démarrage | Consultez docker compose logs <service> |
pre_start ignoré | Compose antérieur à v5.3 | Mettez à jour Compose (docker compose version) |
Init container No such image | L'image du pre_start n'est pas disponible | Tirez-la (docker pull) ou réutilisez l'image du service |
| Changements non appliqués | Compose utilise l'ancienne image/config | docker compose up -d --build --force-recreate |
Limites de Docker Compose
Section intitulée « Limites de Docker Compose »Docker Compose est parfait pour le développement local, mais ce n'est pas un orchestrateur de production : il ne gère qu'une seule machine.
Si votre serveur tombe, vos conteneurs s'arrêtent sans serveur de secours. Si votre application a besoin de plus de ressources, vous ne pouvez pas répartir la charge sur plusieurs serveurs. Pour ces besoins, il faut un véritable orchestrateur.
| Fonctionnalité | Docker Compose | Docker Swarm | Kubernetes |
|---|---|---|---|
| Orchestration multi-serveurs | ❌ | ✅ | ✅ |
| Load balancing automatique | ❌ | ✅ | ✅ |
| Redémarrage sur panne de serveur | ❌ | ✅ | ✅ |
| Scaling automatique (HPA) | ❌ | ❌ | ✅ |
| Rolling updates | ❌ | ✅ | ✅ |
| RBAC et sécurité avancée | ❌ | Basique | ✅ |
| Complexité | Faible | Moyenne | Élevée |
| Cas d'usage | Dev/test/CI | Petit cluster | Production |
Règle simple : Compose en développement ; pour la production, Kubernetes (ou au minimum Docker Swarm).
À retenir
Section intitulée « À retenir »- Docker Compose orchestre plusieurs conteneurs avec un seul fichier YAML et une seule commande.
- Trois concepts : les services (conteneurs), les réseaux (communication) et les volumes (persistance).
docker compose up -ddémarre tout,docker compose downarrête tout,watchsynchronise le code en direct.- Fiabilisez le démarrage avec les healthchecks (
condition: service_healthy) et les init containers (pre_start, Compose v5.3+). - Externalisez vos secrets (
.envou secrets Docker), jamais en clair dans le YAML versionné. - Épinglez chaque image par digest (
@sha256) et scannez-la avec Trivy et Grype. - Compose n'est pas pour la production : pas de haute disponibilité, pas de scaling multi-serveurs.
Checklist
Section intitulée « Checklist »- Docker Compose v5 installé (
docker compose version) - Fichier
compose.yamlcréé et validé (docker compose config) - Images épinglées par digest et scannées (Trivy / Grype)
- Services démarrés (
docker compose up -d) - Communication inter-services fonctionnelle (WordPress accède à MySQL)
- Données persistées (volume
db_data) - Secrets externalisés (
.envou secrets Docker),.envdans.gitignore
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Deux commandes, deux générations
| Commande | Ce que c'est | Statut |
|---|---|---|
docker compose |
Plugin Go intégré à la CLI Docker | Actuel (v5) |
docker-compose |
Ancien binaire Python v1 | Fin de vie |
version: "3", d'où le passage direct à la v5.docker compose version
# Docker Compose version v5.x.x
Pourquoi et comment
Un tag comme:latest peut pointer vers une image différente au fil du temps. Le digest @sha256:... identifie le contenu exact, de façon immuable.docker pull nginx:alpine
docker inspect --format '{{index .RepoDigests 0}}' nginx:alpine
# nginx@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa
services:
web:
image: nginx:alpine@sha256:54f2a904c251d5a34adf545a72d32515a15e08418dae0266e23be2e18c66fefa
Complétez par un scan avec Trivy ou Grype, et automatisez les mises à jour de digests avec Renovate.depends_on ne suffit pas
depends_on garantit que MySQL démarre avant WordPress, mais pas qu'il soit prêt. La solution combine un healthcheck et condition: service_healthy.services:
mysql:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 5
wordpress:
image: wordpress
depends_on:
mysql:
condition: service_healthy
Au démarrage, la séquence est nette : mysql Started puis Waiting puis Healthy, et seulement ensuite wordpress Started.Développement en direct
docker compose watch surveille le code source et met à jour le conteneur automatiquement, sans rebuild manuel.services:
web:
image: nginx:alpine
develop:
watch:
- action: sync
path: ./app
target: /usr/share/nginx/html
docker compose up -d
docker compose watch
Trois actions existent : sync (copie le fichier), rebuild (reconstruit l'image, pour un changement de dépendances) et sync+restart (pour un fichier de configuration).Un seul hôte, pas de haute disponibilité
Docker Compose est excellent en développement, test et CI, mais ne gère qu'une seule machine. Si le serveur tombe, rien ne prend le relais.| Besoin | Compose | Swarm | Kubernetes |
|---|---|---|---|
| Multi-serveurs | ❌ | ✅ | ✅ |
| Redémarrage sur panne serveur | ❌ | ✅ | ✅ |
| Scaling automatique | ❌ | ❌ | ✅ |
Deux méthodes
docker compose up -d --scale web=3
Ou dans le fichier, avec deploy.replicas, désormais honoré par docker compose up (plus seulement par Swarm) :services:
web:
image: nginx:alpine
deploy:
replicas: 3
Le piège des ports
Avec un port fixe, le scaling échoue (port is already allocated). Utilisez une plage de ports : ports:
- "8080-8082:80"
Chaque réplica reçoit alors un port distinct (8080, 8081, 8082).Le champ pre_start (Compose v5.3)
Un init container s'exécute après la création du conteneur de service mais avant son démarrage. Parfait pour une migration de base de données ou préparer un volume, sans polluer l'image applicative.services:
web:
image: nginx:alpine
pre_start:
- command: sh -c "echo 'préparé' > /data/index.html"
volumes:
- web_root:/data
volumes:
web_root:
L'init container partage les volumes du service. Il exige Compose v5.3 ou plus récent.