🔝 Retour au Sommaire
Le fichier docker-compose.yml est le cœur de Docker Compose. C'est dans ce fichier que vous allez décrire toute votre application : quels conteneurs lancer, comment ils communiquent entre eux, quelles ressources ils utilisent, etc.
Dans cette section, nous allons décortiquer la structure de ce fichier pour que vous puissiez créer vos propres configurations en toute confiance.
Avant de plonger dans Docker Compose, il est important de comprendre quelques règles du format YAML :
YAML utilise l'indentation (les espaces en début de ligne) pour définir la structure. Utilisez toujours des espaces, jamais des tabulations.
# ✅ Correct
services:
web:
image: nginx
# ❌ Incorrect (mauvaise indentation)
services:
web:
image: nginxclé: valeur
nom: Docker
port: 8080 ports:
- "8080:80"
- "443:443"
volumes:
- ./data:/app/data
- ./config:/app/config# Ceci est un commentaire
services:
web: # Commentaire en fin de ligne
image: nginxC'est tout ce que vous devez savoir sur YAML pour commencer ! 🎓
Voici le squelette de base d'un fichier Docker Compose :
services:
# Vos conteneurs ici
volumes:
# Vos volumes nommés ici (optionnel)
networks:
# Vos réseaux personnalisés ici (optionnel)Les trois sections principales sont :
- services : La définition de vos conteneurs (obligatoire)
- volumes : La définition des volumes nommés (optionnel)
- networks : La définition des réseaux personnalisés (optionnel)
Examinons chaque section en détail.
💡 Note historique : Dans les anciennes versions de Docker Compose (V1), il était nécessaire d'ajouter une ligne
version: '3.8'en haut du fichier. Avec Docker Compose V2 (intégré comme plugindocker compose), cette ligne n'est plus nécessaire et est ignorée. Vous pouvez simplement l'omettre. Si vous rencontrez d'anciens fichiers avec cette ligne, sachez qu'elle n'a plus d'effet.
C'est la section la plus importante ! C'est ici que vous définissez tous vos conteneurs.
services:
nom-du-service:
image: nom-de-l-image:tag
# autres configurations...Le nom du service (nom-du-service) est important car :
- C'est le nom par lequel les autres services pourront le contacter sur le réseau
- Il apparaîtra dans les logs et commandes Docker Compose
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
backend:
image: node:18
ports:
- "3000:3000"
database:
image: postgres:15
environment:
POSTGRES_PASSWORD: motdepasseDans cet exemple, nous avons trois services : frontend, backend et database.
Voyons maintenant les propriétés les plus courantes que vous pouvez définir pour chaque service.
Spécifie l'image Docker à utiliser pour ce service.
services:
web:
image: nginx:latest
database:
image: postgres:15-alpine
app:
image: mon-utilisateur/mon-app:v1.0Si vous voulez construire une image à partir d'un Dockerfile au lieu d'utiliser une image existante :
services:
app:
build: . # Construit à partir du Dockerfile dans le répertoire courant
# Ou avec plus de détails :
api:
build:
context: ./backend
dockerfile: Dockerfile.devNote : Vous ne pouvez pas utiliser image et build en même temps de manière conflictuelle, mais vous pouvez donner un nom à l'image construite :
services:
app:
build: .
image: mon-app:dev # Nom de l'image une fois construiteExpose les ports du conteneur sur votre machine hôte.
services:
web:
image: nginx
ports:
- "8080:80" # Format: "port-hôte:port-conteneur"
- "443:443"
- "3000:3000"Explication : "8080:80" signifie "le port 80 du conteneur sera accessible sur le port 8080 de ma machine".
Définit les variables d'environnement pour le conteneur.
services:
database:
image: postgres:15
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret123
POSTGRES_DB: ma_base
# Ou avec une autre syntaxe :
app:
image: mon-app
environment:
- NODE_ENV=production
- API_KEY=abc123
- DEBUG=falseMonte des volumes ou des répertoires dans le conteneur.
services:
web:
image: nginx
volumes:
# Bind mount (lier un dossier local)
- ./mon-site:/usr/share/nginx/html
# Volume nommé
- mes-donnees:/var/lib/data
# Volume anonyme
- /var/logIndique qu'un service dépend d'un autre et doit démarrer après lui.
services:
app:
image: mon-app
depends_on:
- database
- cache
database:
image: postgres:15
cache:
image: redis:alpineImportant : depends_on attend seulement que le conteneur démarre, pas qu'il soit prêt à accepter des connexions. Pour des dépendances plus sophistiquées, il existe des solutions que nous verrons plus tard.
Connecte le service à un ou plusieurs réseaux.
services:
web:
image: nginx
networks:
- frontend
api:
image: mon-api
networks:
- frontend
- backend
database:
image: postgres:15
networks:
- backend
networks:
frontend:
backend:Définit la politique de redémarrage du conteneur.
services:
app:
image: mon-app
restart: always # Redémarre toujours si le conteneur s'arrête
worker:
image: mon-worker
restart: unless-stopped # Redémarre sauf si arrêté manuellement
test:
image: mon-test
restart: no # Ne redémarre jamais (par défaut)
critical:
image: critique
restart: on-failure # Redémarre uniquement en cas d'erreurPermet de donner un nom spécifique au conteneur (optionnel).
services:
database:
image: postgres:15
container_name: ma-base-postgresNote : Sans cette option, Docker Compose génère automatiquement un nom comme monprojet_database_1.
Remplace la commande par défaut du conteneur.
services:
app:
image: node:18
command: npm run dev
database:
image: postgres:15
command: postgres -c max_connections=200Définit le répertoire de travail dans le conteneur.
services:
app:
image: node:18
working_dir: /app
volumes:
- ./src:/app
command: npm startCette section permet de définir des volumes nommés qui peuvent être réutilisés par plusieurs services.
services:
app:
image: mon-app
volumes:
- donnees-app:/data
backup:
image: mon-backup
volumes:
- donnees-app:/data:ro # ro = read-only (lecture seule)
volumes:
donnees-app: # Déclaration du volume nomméLes volumes définis ici sont créés par Docker et gérés automatiquement. Ils persistent même si vous supprimez les conteneurs.
volumes:
mes-donnees:
driver: local
driver_opts:
type: none
device: /chemin/sur/l-hote
o: bindPour les débutants, la déclaration simple suffit largement !
Cette section permet de définir des réseaux personnalisés.
services:
web:
image: nginx
networks:
- frontend
api:
image: mon-api
networks:
- frontend
- backend
database:
image: postgres:15
networks:
- backend
networks:
frontend:
backend:Par défaut, si vous ne définissez pas de réseaux, Docker Compose crée automatiquement un réseau par défaut où tous les services peuvent communiquer.
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # Réseau sans accès à InternetVoici un exemple complet qui combine tous ces éléments :
services:
# Service web (frontend)
web:
image: nginx:alpine
container_name: mon-site-web
ports:
- "80:80"
- "443:443"
volumes:
- ./site:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- frontend
depends_on:
- api
restart: unless-stopped
# Service API (backend)
api:
build: ./backend
container_name: mon-api
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: postgresql://database:5432/madb
REDIS_URL: redis://cache:6379
volumes:
- ./backend:/app
- /app/node_modules
networks:
- frontend
- backend
depends_on:
- database
- cache
restart: unless-stopped
# Base de données
database:
image: postgres:15-alpine
container_name: ma-base-donnees
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD} # Utilise une variable d'environnement
POSTGRES_DB: madb
volumes:
- donnees-postgres:/var/lib/postgresql/data
networks:
- backend
restart: unless-stopped
# Cache Redis
cache:
image: redis:alpine
container_name: mon-cache
networks:
- backend
restart: unless-stopped
# Déclaration des volumes nommés
volumes:
donnees-postgres:
# Déclaration des réseaux
networks:
frontend:
backend:services:
# Service principal de l'application
app:
image: mon-app
# Exposition sur le port 8080 pour le développement
ports:
- "8080:8000"# ✅ Bon
services:
api-utilisateurs:
image: mon-api
database-principale:
image: postgres
# ❌ Moins clair
services:
svc1:
image: mon-api
db:
image: postgresservices:
# --- Frontend ---
web:
image: nginx
interface-admin:
image: admin-ui
# --- Backend ---
api:
image: api-service
worker:
image: worker-service
# --- Data ---
database:
image: postgres
cache:
image: redisCréez un fichier .env à côté de votre docker-compose.yml :
DB_PASSWORD=supersecret
API_KEY=abc123xyz Puis utilisez-les dans votre fichier :
services:
database:
image: postgres
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
api:
image: mon-api
environment:
API_KEY: ${API_KEY}Important : N'oubliez pas d'ajouter .env dans votre .gitignore pour ne pas commiter les secrets !
# ❌ Erreur : mauvaise indentation
services:
web:
image: nginx
# ✅ Correct
services:
web:
image: nginx# ❌ Peut causer des problèmes
ports:
- 8080:80
# ✅ Recommandé
ports:
- "8080:80"YAML n'accepte que les espaces. Si vous avez une erreur de parsing, vérifiez que vous n'avez pas utilisé des tabulations.
# ❌ Erreur : manque les deux-points
services:
web
image: nginx
# ✅ Correct
services:
web:
image: nginxPour vérifier que votre fichier est correctement formaté, utilisez la commande :
docker compose configCette commande affiche la configuration finale (avec toutes les valeurs par défaut) et vous indique s'il y a des erreurs de syntaxe.
✅ Le fichier docker-compose.yml utilise le format YAML avec une indentation stricte (espaces uniquement)
✅ La section services est obligatoire et contient la définition de vos conteneurs
✅ Les sections volumes et networks sont optionnelles mais utiles pour organiser votre application
✅ Les propriétés principales d'un service sont : image, build, ports, environment, volumes, depends_on
✅ Utilisez des commentaires et des noms explicites pour rendre votre fichier lisible
✅ Utilisez des variables d'environnement (fichier .env) pour les données sensibles
✅ Validez votre fichier avec docker compose config avant de l'utiliser
Prochaine section : Nous allons voir comment définir plusieurs services et les faire communiquer entre eux dans des applications réelles !