Introduction
Les Docker Compose advanced concepts ne consistent pas à « ajouter des conteneurs », mais à maîtriser comment un ensemble de services est construit, démarré, découvert, configuré, sécurisé et observé comme une seule unité. Dans ce guide, vous allez :
- Comprendre les Docker Compose internals pour anticiper le comportement.
- Appliquer des fonctionnalités avancées : profils, healthchecks avec dépendances conditionnelles, secrets et configs, anchors YAML, et superposition multi-fichiers.
- Lancer un pilote local ciblé qui prouve la valeur sans risque pour la production.
Ce texte sert de Docker Compose deep dive pragmatique, avec des Docker Compose examples directement utilisables et une vue claire de la Docker Compose architecture côté hôte.
Vue d'ensemble du flux de travail
Utilisez cette séquence pour introduire les fonctionnalités de Compose en sécurité :
- Concevoir le graphe de services
- Définissez services, frontières de données et ports exposés. Choisissez des volumes nommés pour l'état.
- Construire
- Utilisez build context, multi-stage targets et build args. Préférez BuildKit avec transfert SSH si vous récupérez des dépendances privées.
- Exécuter
- Démarrez avec un nom de projet, des profils pour les outils facultatifs et des healthchecks. Utilisez depends_on avec des conditions pour contrôler le démarrage.
- Observer
- Streamez les logs, inspectez l'état de santé et interrogez les noms DNS des conteneurs sur le réseau du projet.
- Durcir
- Ajoutez des systèmes de fichiers en lecture seule lorsque possible, définissez des ulimits et montez les secrets en fichiers. Évitez deploy.* sauf en mode Swarm.
Internes de Compose qui comptent
Ces détails éliminent la plupart des surprises :
- Nom de projet
- Compose regroupe tout par un nom de projet (top-level
name:ou-pcôté CLI). Réseaux et volumes sont créés avec ce préfixe, isolant les services entre projets sur le même hôte.
- Réseau par défaut
- Compose crée un réseau bridge défini par l'utilisateur, par projet. Chaque nom de service devient un hostname DNS sur ce réseau (par exemple,
dbrésout vers le conteneur Postgres). Pas besoin delinks.
- Fusion de fichiers
- Plusieurs fichiers
-fsont fusionnés de haut en bas. Les derniers écrasent/étendent les premiers. Maintenez un fichier de base stable et superposez des changements spécifiques à l'environnement.
- Résolution des variables d'environnement
- Compose supporte
${VAR}et${VAR:-default}dans le YAML. Il lit.envdans le répertoire du projet et l'environnement shell courant. Les variables du shell priment sur.env.env_fileau niveau service injecte des variables dans ce conteneur, sans affecter la substitution au niveau Compose.
- Ordre de démarrage et disponibilité
depends_onsans conditions ordonne le démarrage des conteneurs, pas leur « readiness ». Utilisez unhealthchecketdepends_onaveccondition: service_healthypour attendre la disponibilité lorsque votre version de Compose le permet.
- Statut de santé
- Un service avec healthcheck rapporte
healthy,startingouunhealthy. Interrogez-le viadocker compose psetdocker compose logs.
- Clés spécifiques Swarm
- Les clés sous
deploy.*concernent Swarm. En exécution classique sur un seul hôte, Compose ignore l'essentiel. Utilisez les options de service (environment,volumes,ulimits,read_only, etc.) hors Swarm.
Concepts avancés avec exemples
Ci-dessous, un fichier de base « orienté production » montrant plusieurs schémas avancés. Il exécute un service web en frontal Nginx, Postgres et Redis. On y trouve profils, healthchecks, secrets, configs, champs d'extension et parades de sécurité.
# compose.yml
name: myapp
# Champs d'extension et ancres pour la réutilisation
x-service-defaults: &service_defaults
restart: unless-stopped
networks:
- appnet
env_file:
- ./.env
init: true
x-healthchecks:
postgres: &pg_health
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
interval: 3s
timeout: 3s
retries: 10
redis: &redis_health
test: ["CMD", "redis-cli", "ping"]
interval: 3s
timeout: 3s
retries: 10
web: &web_health
test: ["CMD", "wget", "-qO-", "http://localhost/healthz"]
interval: 5s
timeout: 3s
retries: 10
services:
db:
<<: *service_defaults
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck: *pg_health
secrets:
- db_password
ulimits:
nofile: 65535
cache:
<<: *service_defaults
image: redis:7
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redisdata:/data
healthcheck: *redis_health
web:
<<: *service_defaults
build:
context: ./web
dockerfile: Dockerfile
target: runtime
args:
APP_ENV: ${APP_ENV:-dev}
ssh:
- default
depends_on:
db:
condition: service_healthy
cache:
condition: service_healthy
ports:
- "8080:80"
healthcheck: *web_health
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges: true
configs:
- source: nginx_conf
target: /etc/nginx/conf.d/app.conf
adminer:
<<: *service_defaults
image: adminer:4
profiles: ["tools"]
ports:
- "8081:8080"
configs:
nginx_conf:
file: ./deploy/nginx/app.conf
secrets:
db_password:
file: ./secrets/db_password.txt
networks:
appnet: {}
volumes:
pgdata: {}
redisdata: {}
Points clés :
name: myappfixe le nom de projet pour un préfixe réseau/volume stable.- Les ancres (
x-service-defaults,x-healthchecks) réduisent la duplication. - Healthchecks +
depends_onconditionnel bloquent le démarrage dewebtant que Postgres et Redis ne sont pas prêts. secretsetconfigsmontent des fichiers dans les conteneurs ; protégez les permissions côté hôte.read_onlyetno-new-privilegesdurcissent le conteneur web, ettmpfspour/tmpévite les écritures sur l'image.- Les
profilesactivent des outils optionnels (ex.adminer) à la demande.
Surcharges locales pour itérer
Utilisez un second fichier pour monter le code source et activer des flags de debug, sans toucher au fichier de base.
# compose.override.yml (pris en charge automatiquement par docker compose)
services:
web:
volumes:
- ./web/src:/var/www/src: rw, cached
environment:
DEBUG: "1"
Pour des changements spécifiques à un environnement qui ne doivent pas être chargés automatiquement, créez un fichier distinct et passez-le explicitement.
# compose.prod.yml
services:
web:
environment:
APP_ENV: prod
ports:
- "80:80" # publier sur le port standard en prod
adminer:
profiles: ["never"] # désactiver les outils en prod
Exécuter avec :
# Base + surcouche prod explicite
docker compose -f compose.yml -f compose.prod.yml up -d
Variables d'environnement et .env
Créez un fichier .env dans le répertoire du projet pour la substitution au niveau Compose et des valeurs communes :
# .env
APP_ENV=dev
POSTGRES_PASSWORD=unused_when_using_secret
# Vous avez toujours besoin de secrets/db_password.txt pour le secret fichier
Notes :
- Les variables du shell priment sur
.envpour la substitution. Exemple :APP_ENV=staging docker compose uputiliserastaging. env_filesous un service injecte des variables dans ce conteneur uniquement.
Multi-stage builds avec targets et SSH
Utilisez le multi-stage pour garder une image runtime petite et récupérer des dépendances privées de manière sécurisée.
# web/Dockerfile
FROM golang:1.22 AS build
WORKDIR /src
# optionnel : BuildKit SSH pour deps privées
# RUN --mount=type=ssh go env -w GOPRIVATE=github.com/yourorg/*
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app
FROM nginx:1.27-alpine AS runtime
COPY --from=build /out/app /usr/local/bin/app
COPY deploy/nginx/app.conf /etc/nginx/conf.d/app.conf
# endpoint de santé simple
HEALTHCHECK --interval=5s --timeout=3s --retries=10 CMD wget -qO- http://localhost/healthz || exit 1
Utilisation de BuildKit :
# Activer BuildKit et l'agent SSH pour les dépôts privés
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
ssh-add -l >/dev/null 2>&1 || ssh-add
docker compose build --ssh default
Plan de pilote local
Démarrez par un pilote restreint, mesurable, qui exerce les fonctionnalités les plus utiles sans surcomplexité.
Objectifs du pilote :
- Prouver que le démarrage dépend de la santé (web attend db et cache).
- Valider les montages de
secretsetconfigs. - Confirmer le périmètre de projet et la découverte de services via le réseau applicatif.
Préparation :
- Créez les répertoires et fichiers
mkdir -p deploy/nginx secrets web/src
printf 'server {\n listen 80;\n location /healthz { return 200 "ok"; }\n location / { return 200 "hello"; }\n}\n' > deploy/nginx/app.conf
umask 077 && printf 'supersecretpassword\n' > secrets/db_password.txt
- Optionnel : ajoutez
.envavecAPP_ENV=dev
Exécuter le pilote :
# Lancer la pile de base et, si besoin, le profil d'outils
docker compose up -d --build
# ou inclure les outils
docker compose --profile tools up -d --build
Valider :
# Vérifier l'état et la santé des services
docker compose ps
# Attendre l'état healthy (versions récentes)
docker compose up --wait
# Taper l'endpoint web
curl -sS http://localhost:8080/healthz
# Valider la découverte DNS de web vers db
docker compose exec web getent hosts db
# Vérifier le montage des secrets dans db
docker compose exec db ls -l /run/secrets
Observer et itérer :
docker compose logs -f web db cachemontre la séquence de démarrage.- Si les healthchecks échouent, inspectez les tests et les logs pour ajuster timings et commandes.
Nettoyer proprement :
docker compose down --volumes
Astuces pratiques et défauts sûrs
- Utilisez des volumes nommés pour les bases de données ; évitez de binder un dossier de DB depuis l'hôte.
- Conservez le réseau de projet par défaut. Publiez uniquement les ports nécessaires.
- Préférez healthchecks +
depends_onconditionnels aux scripts d'attente ad hoc. - Utilisez des
profilespour garder les outils facultatifs désactivés par défaut. - Évitez
deploy.*si vous n'êtes pas en mode Swarm. - Traitez les secrets locaux comme sensibles : restreignez les permissions de
./secretset ne les validez pas en VCS. - Fixez les tags d'images pour les services de base (ex.
postgres:16) pour éviter les mises à jour surprises.
Conclusion
Vous disposez maintenant d'un modèle mental clair de la façon dont Docker Compose regroupe les services, câble le réseau et la découverte, résout la configuration et impose l'état de santé. Commencez par le pilote local pour valider le démarrage conditionné par la santé, les secrets et les configs. Ensuite, superposez des fichiers spécifiques d'environnement, durcissez avec des systèmes de fichiers en lecture seule et no-new-privileges, et gardez les outils optionnels derrière des profils. Cette approche progressive réduit les risques tout en tirant pleinement parti des Docker Compose advanced concepts, d'un Docker Compose deep dive pragmatique et de Docker Compose internals utiles au quotidien.