10 - Docker Compose avance
Ce que tu vas apprendre
- Les profiles pour activer des services uniquement en dev
- Les fichiers override et la fusion de configurations
- La directive extends pour factoriser
- Les ancres YAML pour éviter la répétition
- Docker Compose Watch pour le rechargement automatique
- La directive include pour les gros projets
Prerequisites
- Avoir compris les bases de Docker Compose
- Docker Compose v2.20+ pour les fonctionnalités recentes
Une fois que tu maitrises le compose.yaml de base, tu te retrouves vite avec un fichier de 200 lignes ou tu repetes les memes blocs partout. Docker Compose a des mecanismes pour gerer ca proprement. Je les ai tous utilises sur paltemps.fr, et certains m'ont fait gagner des heures.
Profiles : des services a la carte
Tu as un service Mailhog pour intercepter les mails en dev. Pas question de le lancer en production. Les profiles resolvent ca :
yamlservices:
app:
build: .
ports:
- "3000:3000"
mailhog:
image: mailhog/mailhog
ports:
- "8025:8025"
profiles:
- dev
adminer:
image: adminer
ports:
- "8080:8080"
profiles:
- dev
- debug
Par défaut, docker compose up ne lance que les services sans profil. Pour activer un profil :
bashdocker compose --profile dev up -d
Tu peux aussi définir la variable d'environnement COMPOSE_PROFILES=dev dans ton .env. Plusieurs profils se separent par une virgule.
Override files : la fusion automatique
Compose fusionne automatiquement compose.yaml et compose.override.yaml quand les deux existent. C'est le mecanisme que j'utilise le plus.
Le fichier principal, compose.yaml :
yamlservices:
app:
build: .
ports:
- "3000:3000"
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
Le fichier compose.override.yaml (charge automatiquement) :
yamlservices:
app:
volumes:
- .:/app
command: node --watch src/index.js
environment:
DEBUG: "true"
Quand tu lances docker compose up, les deux fichiers sont fusionnes. Le service app aura les ports du premier fichier ET les volumes et la commande du second.
Pour utiliser un fichier spécifique a la place :
bashdocker compose -f compose.yaml -f compose.prod.yaml up -d
On exploite ce pattern en détail dans l'article dev vs prod.
extends : factoriser les services
Quand plusieurs services partagent la meme configuration de base, extends évité la duplication :
yamlservices:
base-node:
build: .
environment:
NODE_ENV: production
deploy:
resources:
limits:
memory: 512M
api:
extends:
service: base-node
ports:
- "3000:3000"
command: node dist/api.js
worker:
extends:
service: base-node
command: node dist/worker.js
api et worker heritent de base-node et ajoutent leurs spécificités. Le service base-node ne sera pas démarré lui-meme (sauf si tu lui ajoutes un command).
Tu peux aussi extends un service depuis un autre fichier :
yamlservices:
api:
extends:
file: common.yaml
service: base-node
Ancres YAML : la magie du &
YAML supporte nativement les ancres et les alias. C'est du YAML pur, pas une fonctionnalité Docker. Mais c'est dans les fichiers Compose que tu les verras le plus.
yamlx-common-env: &common-env
TZ: Europe/Paris
NODE_ENV: production
x-healthcheck: &default-healthcheck
interval: 10s
timeout: 5s
retries: 3
services:
api:
build: .
environment:
<<: *common-env
PORT: "3000"
healthcheck:
<<: *default-healthcheck
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
worker:
build: .
environment:
<<: *common-env
QUEUE: default
healthcheck:
<<: *default-healthcheck
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
Le &common-env créé une ancre. Le *common-env la référencé. Le <<: fusionne le contenu dans le mapping courant. Les clés apres <<: ecrasent celles de l'ancre.
Les blocs x- en racine sont des extensions personnalisees. Compose les ignore, mais ils sont parfaits pour stocker des ancres.
Docker Compose Watch
Depuis Compose v2.22, docker compose watch surveille tes fichiers et reagit aux changements sans redemarrer manuellement :
yamlservices:
app:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: package.json
Trois actions possibles :
- sync : copie les fichiers modifies dans le conteneur (comme un bind mount intelligent)
- rebuild : reconstruit l'image et relance le conteneur
- sync+restart : copie les fichiers et relance le conteneur
bashdocker compose watch
L'avantage sur un bind mount classique ? Watch gere les différences de système de fichiers entre host et conteneur, et tu peux choisir l'action par type de fichier.
La directive include
Pour les gros projets avec plusieurs fichiers Compose, include permet de les combiner :
yamlinclude:
- path: ./infra/compose.yaml
- path: ./monitoring/compose.yaml
services:
app:
build: .
depends_on:
- db # defini dans infra/compose.yaml
Chaque fichier inclus garde son propre contexte de build. C'est plus propre que la fusion manuelle avec -f.
Compose merge : combiner des fichiers
La commande docker compose config montre le résultat de la fusion de tous tes fichiers :
bashdocker compose -f compose.yaml -f compose.override.yaml config
Ca affiche le YAML final, apres fusion. C'est indispensable pour debugger quand tu ne comprends pas pourquoi un service a un mauvais port ou une mauvaise variable.
Résumé
- Les profiles activent des services a la demande (
--profile dev) - Le fichier override est fusionne automatiquement, parfait pour les configs dev
- extends factorise les services qui partagent une base commune
- Les ancres YAML (
&,*,<<:) eliminent la répétition dans le fichier - watch synchronise les fichiers et relance les builds automatiquement
- include decoupe un gros Compose en plusieurs fichiers independants
Navigation : Precedent : 09 - Compose bases | Suivant : 11 - Networking bases
Sources
- Docker Compose profiles par Docker
- Docker Compose Watch par Docker
- YAML anchors and aliases par YAML Spec