Ce guide vous apprend à déployer une application multi-conteneurs avec Docker Compose en 15 minutes. Vous saurez écrire un fichier docker-compose.yml, faire communiquer vos services (application web + base de données), persister vos données avec des volumes et gérer vos secrets. Prérequis : Docker installé. Résultat : une stack WordPress + MySQL fonctionnelle que vous pourrez adapter à vos projets.
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 docker-compose.yml multi-services : créer une stack WordPress + MySQL complète avec dépendances, volumes et variables
- Orchestrer avec les commandes CLI : maîtriser
up,down,logs,exec,configetscalepour gérer vos environnements - Gérer les configurations multi-environnements : utiliser fichiers
.env, overrides et profils pour dev/staging/prod - Résoudre les problèmes courants : diagnostiquer erreurs de connexion, ports occupés, volumes perdus et dépendances non prêtes
- Connaître les limites vs orchestrateurs : identifier quand migrer vers Docker Swarm ou Kubernetes pour la production
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 devez exécuter manuellement chaque commande, dans le bon ordre, en vous souvenant de toutes les options. Si vous faites une erreur, vous devez tout recommencer. 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 docker-compose.yml |
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 dans les environnements où vous contrôlez une seule machine et où la haute disponibilité n’est pas critique. C’est l’outil idéal pour les développeurs qui veulent reproduire un environnement de production localement, ou pour les équipes QA qui ont besoin d’environnements de test isolés.
En revanche, dès que vous avez besoin de répartir la charge sur plusieurs serveurs, de gérer des pannes automatiquement, ou de déployer en production 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 → utilisez 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. Si docker compose ne fonctionne pas, vous avez peut-être une ancienne version de Docker.
Si docker compose version échoue, installez le plugin :
# Ubuntu/Debiansudo apt updatesudo apt install docker-compose-plugin
# Vérificationdocker compose versionValidation : la commande doit afficher quelque chose comme Docker Compose version v2.x.x.
Concepts 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, etc. 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 peuvent s’échanger des données. C’est comme un réseau local virtuel : les conteneurs connectés au même réseau peuvent se « voir », tandis que ceux sur des réseaux différents sont isolés.
La magie 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 peut contacter la base de données simplement en utilisant mysql comme nom d’hôte — pas besoin de connaître son adresse IP.
Docker Compose crée automatiquement un réseau par défaut nommé <dossier>_default. Tous les services de votre fichier y sont connectés, ce qui signifie qu’ils peuvent communiquer entre eux sans configuration supplémentaire. Vous pouvez aussi créer des réseaux personnalisés pour isoler certains services (par exemple, 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 différent :
| 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 docker-compose.yml
Section intitulée « Votre premier docker-compose.yml »Pour illustrer ces concepts, nous allons déployer une stack simple : **WordPress
- MySQL**. Suivez ces étapes pour créer votre fichier
docker-compose.ymlet lancer les conteneurs.
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
docker-compose.ymlFenêtre de terminal touch docker-compose.yml -
Ajoutez la configuration suivante
services:wordpress:image: wordpress:latestports:- "8080:80"environment:WORDPRESS_DB_HOST: mysqlWORDPRESS_DB_USER: wordpressWORDPRESS_DB_PASSWORD: wordpress_passwordWORDPRESS_DB_NAME: wordpressdepends_on:- mysqlrestart: unless-stoppedmysql:image: mysql:8.0environment:MYSQL_DATABASE: wordpressMYSQL_USER: wordpressMYSQL_PASSWORD: wordpress_passwordMYSQL_ROOT_PASSWORD: root_secret_passwordvolumes:- db_data:/var/lib/mysqlrestart: unless-stoppedvolumes:db_data:Explications ligne par ligne :
services:— définit les conteneurs à créerimage: wordpress:latest— utilise l’image officielle WordPressports: "8080:80"— expose le port 80 du conteneur sur le port 8080 de votre machineenvironment:— variables d’environnement passées au conteneurWORDPRESS_DB_HOST: mysql— WordPress contacte MySQL via son nom de servicedepends_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éesrestart: unless-stopped— redémarre automatiquement sauf arrêt manuel
Lancement de la stack
Section intitulée « Lancement de la stack »Lorsque vous exécutez docker compose up, Docker Compose orchestre l’ensemble du processus de 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 :
NAME STATUS PORTSmon-wordpress-mysql-1 Up 30 seconds 3306/tcp, 33060/tcpmon-wordpress-wordpress-1 Up 30 seconds 0.0.0.0:8080->80/tcp -
Testez l’application
Ouvrez votre navigateur à l’adresse : http://localhost:8080
Vous devriez voir l’écran d’installation de WordPress.
-
Consultez les logs si quelque chose ne fonctionne pas
Fenêtre de terminal docker compose logs# Ou pour un service spécifique :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 docker-compose.yml pose deux problèmes : d’abord, c’est un risque de sécurité si vous versionnez ce fichier (les secrets se retrouvent dans l’historique Git). Ensuite, c’est peu pratique si vous avez des environnements différents (dev, staging, prod) avec des credentials différents.
La solution : externaliser vos variables dans un fichier .env. Docker Compose lit automatiquement ce fichier s’il existe dans le même dossier que votre docker-compose.yml, et remplace les variables ${...} par leurs valeurs.
# Fichier .env (même dossier que docker-compose.yml)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 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_PASSWORD: ${MYSQL_PASSWORD}Gestion des secrets (production)
Section intitulée « Gestion des secrets (production) »Les fichiers .env sont pratiques, mais ils ont une limite : les variables d’environnement sont visibles dans les logs, les processus, et via docker inspect. Pour des secrets vraiment sensibles (mots de passe de production, clés API), Docker propose un mécanisme plus sécurisé : les secrets.
Avec 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. C’est plus sûr car le secret n’apparaît jamais dans les variables d’environnement ni dans les logs.
services: mysql: image: mysql:8.0 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, jamais exposé dans les variables d’environnement ou les logs.
Dépendances et healthchecks
Section intitulée « Dépendances et healthchecks »Vous avez peut-être 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 » !
Quand Docker lance le conteneur MySQL, il considère le service comme « démarré » dès que le processus MySQL est lancé. Mais MySQL a besoin de quelques secondes pour initialiser ses bases de données et ouvrir son port réseau. Si WordPress tente de se connecter pendant cette initialisation, il échouera 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 avant de démarrer.
services: mysql: image: mysql:8.0 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 # ... reste de la config
wordpress: image: wordpress:latest depends_on: mysql: condition: service_healthy # ... reste de la configAvec condition: service_healthy, WordPress attendra que MySQL réponde au ping avant de démarrer.
Build d’images personnalisées
Section intitulée « Build d’images personnalisées »Jusqu’ici, nous avons utilisé des images publiques (wordpress:latest, mysql:8.0). Mais dans un projet réel, vous aurez souvent votre propre code à conteneuriser. Plutôt que de builder l’image manuellement avec docker build, puis de la référencer dans Compose, vous pouvez demander à Compose de la construire automatiquement.
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 # Nom du Dockerfile (optionnel si c'est le nom par défaut) ports: - "3000:3000"Quand vous lancez docker compose up --build, Compose construit d’abord l’image à partir du Dockerfile, puis lance le conteneur. C’est particulièrement pratique en développement : modifiez votre code, relancez avec --build, et vous avez une nouvelle image.
Scaling et réplication
Section intitulée « Scaling et réplication »L’un des principaux avantages de Docker Compose est sa capacité à scaler horizontalement un service en créant plusieurs réplicas (copies identiques) du même conteneur. C’est utile pour répartir la charge, tester la montée en charge, ou simuler un environnement distribué.
# Lancer 3 instances du service webdocker compose up -d --scale web=3
# Vérifier les conteneurs créésdocker compose psRésultat attendu :
NAME STATUS PORTSmon-projet-web-1 Up 10 seconds 0.0.0.0:8080->80/tcpmon-projet-web-2 Up 10 seconds 0.0.0.0:8081->80/tcpmon-projet-web-3 Up 10 seconds 0.0.0.0:8082->80/tcpVous pouvez aussi définir le nombre de réplicas directement dans le fichier Compose (syntaxe Swarm, compatible avec Compose v3+) :
services: web: image: nginx:latest deploy: replicas: 3Limitations du scaling avec Compose :
- Pas de vrai load balancer intégré (il faut un reverse proxy)
- Pas de répartition intelligente de la charge
- Pas de health-based scaling (augmenter/réduire selon la charge CPU)
Pour ces besoins avancés, tournez-vous vers 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 de vos applications.
Docker Compose propose 4 politiques, chacune adaptée à un cas d’usage spécifique :
| Politique | Comportement | Usage recommandé |
|---|---|---|
no | Ne jamais redémarrer automatiquement (par défaut) | Services à usage ponctuel, jobs batch |
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 (docker compose stop) | Services persistants en production |
on-failure | Redémarre uniquement si le conteneur a crashé (exit code ≠ 0) | Services instables, diagnostics |
Exemple de configuration :
services: db: image: postgres:15 restart: always # BDD toujours disponible
api: image: mon-api:latest restart: unless-stopped # Ne redémarre pas si arrêté volontairement
worker: image: worker:latest restart: on-failure # Redémarre uniquement en cas de crash
batch: image: batch-job:latest restart: no # Job unique, pas de redémarrageVérifier l’historique de redémarrage :
docker inspect <container_id> | grep -A 5 RestartCountProfils : services optionnels
Section intitulée « Profils : services optionnels »Les profils permettent de définir des services optionnels qui ne démarrent que si explicitement demandés. C’est particulièrement utile pour :
- Les outils de debug (phpmyadmin, pgadmin, adminer)
- Les services de développement (hot-reload, linters)
- Les environnements de test (mocks, stubs)
Exemple avec profils debug :
services: db: image: postgres:15 # Toujours démarré (pas de profil)
api: image: mon-api:latest # Toujours démarré
pgadmin: image: dpage/pgadmin4 profiles: ["debug"] # Démarré uniquement avec --profile debug ports: - "5050:80"
prometheus: image: prom/prometheus profiles: ["monitoring"] # Démarré uniquement avec --profile monitoringUtilisation :
# Démarrage normal : db + api uniquementdocker compose up -d
# Démarrage avec pgadmin pour debugdocker compose --profile debug up -d
# Démarrage avec monitoringdocker compose --profile monitoring up -d
# Combiner plusieurs profilsdocker compose --profile debug --profile monitoring up -dCas d’usage réels :
| Profil | Services | Utilisation |
|---|---|---|
debug | pgadmin, phpmyadmin, redis-commander | Exploration BDD en dev |
monitoring | prometheus, grafana | Métriques et dashboards |
test | wiremock, mock-api | Tests d’intégration |
docs | swagger-ui, redoc | Documentation API |
Multi-fichiers et environnements
Section intitulée « Multi-fichiers et environnements »Dans un projet réel, vous avez souvent besoin de configurations différentes selon l’environnement : développement (avec hot-reload), staging (avec logs verbeux), production (avec limites ressources strictes).
Docker Compose supporte plusieurs fichiers YAML qui se fusionnent automatiquement. C’est plus maintenable que de dupliquer toute la configuration dans plusieurs fichiers séparés.
Structure recommandée :
mon-projet/├── docker-compose.yml # Configuration de base (commune à tous les envs)├── docker-compose.override.yml # Overrides pour dev (auto-chargé)├── docker-compose.prod.yml # Overrides pour production├── docker-compose.test.yml # Overrides pour tests├── .env.dev # Variables dev├── .env.prod # Variables prod└── .env.test # Variables testdocker-compose.yml (base commune) :
services: api: image: mon-api:${VERSION:-latest} environment: DB_HOST: db DB_NAME: ${DB_NAME}docker-compose.override.yml (dev — chargé automatiquement) :
services: api: build: ./api # Build local au lieu d'utiliser l'image volumes: - ./api:/app # Hot reload environment: DEBUG: "true" ports: - "3000:3000" # Expose pour accès directdocker-compose.prod.yml (production) :
services: api: deploy: replicas: 3 resources: limits: cpus: '0.5' memory: 512M restart: unless-stopped # Pas de ports exposés (via reverse proxy)Utilisation selon l’environnement :
# Développement (charge base + override automatiquement)docker compose up -d
# Production (base + prod, ignore override)docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# Test (base + test)docker compose -f docker-compose.yml -f docker-compose.test.yml up -dDifférences entre développement et production :
Fusion des propriétés :
| Type de propriété | Comportement |
|---|---|
Scalaires (image, restart) | Écrasement : dernier fichier gagne |
Listes (ports, volumes) | Fusion : combinaison des deux listes |
Maps (environment, labels) | Fusion : clés dupliquées écrasées |
Exemple de fusion :
# Fichier 1environment: DEBUG: "false" API_KEY: "dev-key"
# Fichier 2environment: DEBUG: "true" LOG_LEVEL: "info"
# Résultat fusionnéenvironment: DEBUG: "true" # Écrasé API_KEY: "dev-key" # Conservé LOG_LEVEL: "info" # AjoutéCommandes essentielles
Section intitulée « Commandes essentielles »Voici les commandes que vous utiliserez quotidiennement. La plupart s’exécutent depuis le dossier contenant votre docker-compose.yml. Si vous êtes ailleurs, utilisez l’option -f pour spécifier le chemin du fichier.
| Commande | Description |
|---|---|
docker compose up -d | Démarre tous les services en arrière-plan |
docker compose down | Arrête et supprime les 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 logs -f | Affiche les logs en temps réel |
docker compose exec mysql bash | Ouvre un shell dans le conteneur MySQL |
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 »Même avec un fichier Compose bien configuré, des problèmes peuvent survenir. Voici les erreurs les plus fréquentes et comment les résoudre. Dans tous les cas, votre premier réflexe devrait être de 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 8080 | Changez le port dans ports: ou arrêtez l’autre service |
| WordPress affiche “Error establishing database connection” | MySQL n’est pas encore prêt ou mauvais credentials | Vérifiez les variables d’environnement, ajoutez un healthcheck |
Les données disparaissent après docker compose down | Vous avez utilisé down -v qui supprime les volumes | Utilisez down sans -v pour garder les données |
network not found | Le réseau a été supprimé manuellement | Relancez docker compose up pour le recréer |
| Conteneur en restart loop | L’application plante au démarrage | Consultez docker compose logs <service> |
| Changements de config non appliqués | Compose utilise l’ancienne image/config | Lancez 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. Pourquoi ? Parce qu’il ne gère qu’une seule machine.
Imaginons que votre serveur tombe en panne. Avec Compose, vos conteneurs s’arrêtent et ne redémarrent pas — il n’y a pas de serveur de secours. Imaginons que votre application ait besoin de plus de ressources. Avec Compose, vous ne pouvez pas répartir la charge sur plusieurs serveurs.
Pour ces besoins, vous avez besoin d’un véritable orchestrateur : Docker Swarm (plus simple) ou Kubernetes (plus puissant). Voici une comparaison pour vous aider à choisir :
| 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 : utilisez Compose en développement. Pour la production, passez à 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. -
Externalisez vos secrets dans un fichier
.env(jamais en clair dans le YAML versionné). -
Utilisez des healthchecks pour que les dépendances attendent que les services soient vraiment prêts.
-
Compose n’est pas pour la production : pas de haute disponibilité, pas de scaling multi-serveurs.
Checklist
Section intitulée « Checklist »- Docker Compose installé (
docker compose versionfonctionne) - Fichier
docker-compose.ymlcréé et validé (docker compose config) - Services démarrés (
docker compose up -d) - Communication inter-services fonctionnelle (WordPress accède à MySQL)
- Données persistées (volume
db_datacréé) - Secrets externalisés (fichier
.envou secrets Docker) - Fichier
.envdans.gitignore