Déploiement Docker Compose en production : trois piliers — healthcheck, restart et limites de ressources

Une alerte SMS vous arrache du sommeil.
Vous ouvrez l’ordinateur : le conteneur affiche running, pastille verte, tout semble sain. Mais le service ? 502 Bad Gateway.
Le conteneur base de données n’avait pas fini de démarrer quand l’application s’est déjà précipitée pour s’y connecter. Échec de connexion, service down. Le conteneur « tourne » encore, mais le service est mort.
C’est ce qui m’est arrivé la première fois que j’ai déployé Docker Compose en production.
Faire tourner et faire tourner de façon stable, ce n’est pas la même chose. docker-compose up en un clic ne garantit pas que tout tienne debout à 3 h du matin quand la mémoire explose ou qu’un processus crash.
Les trois piliers du déploiement Docker Compose en production — healthcheck, politique de redémarrage, limites de ressources — comblent précisément ce fossé. Cet article partage la méthode de configuration tirée de mes galères, avec un modèle YAML prêt à copier, pour passer de « ça tourne » à « ça tient la route ».
1. Healthcheck : vérifier que le conteneur est réellement utilisable
L’état running de docker ps signifie seulement que le processus du conteneur est encore là. Est-ce qu’il sert correctement ? Aucune idée.
Le healthcheck, c’est Docker qui « examine » régulièrement votre conteneur : une requête HTTP, un ping base de données, ou un script — pour voir si le service est vraiment vivant.
Comment fonctionne le healthcheck ?
Docker envoie la commande de vérification à l’intervalle défini. Retour 0 = sain, non nul = malsain. Après plusieurs échecs consécutifs, le conteneur passe en unhealthy.
Point clé : un échec de healthcheck ne déclenche pas automatiquement un redémarrage. Il expose seulement l’état. Pour l’auto-récupération, combinez-le avec depends_on conditionnel et la politique de redémarrage.
Quatre paramètres à maîtriser
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s # intervalle entre les vérifications
timeout: 10s # délai max. d'une vérification
retries: 3 # échecs consécutifs avant unhealthy
start_period: 60s # période de grâce, échecs non comptés dans retries
J’avais ignoré start_period un temps : démarrage lent, 40 s pour la base, healthcheck dès 10 s. Trois échecs, unhealthy direct. Avec start_period: 60s, l’application a le temps de s’initialiser.
Commandes healthcheck courantes
Service Web :
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
PostgreSQL :
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Redis :
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
Démarrage conditionnel avec depends_on
Là où le healthcheck brille vraiment : attendre que les dépendances soient prêtes avant de lancer le service.
services:
app:
depends_on:
db:
condition: service_healthy # attendre le healthcheck DB
redis:
condition: service_healthy # attendre le healthcheck Redis
Avant, j’utilisais depends_on: [db, redis] : l’app démarrait pendant que la base s’initialisait encore. Connexion impossible, crash. Avec condition: service_healthy, l’app attend que pg_isready réponde. Enfin du calme.
2. Politique de redémarrage (restart) : auto-réparation
Conteneur tombé, qui le relève ?
Un docker restart manuel à 3 h du matin quand l’alerte sonne ? Bon courage.
La politique de redémarrage délègue ça au démon Docker : après une sortie du conteneur, Docker décide s’il faut redémarrer.
Comparaison des quatre politiques
| Politique | Comportement | Cas d’usage |
|---|---|---|
no | Pas de redémarrage | Tests temporaires, CI/CD |
always | Redémarrage quelle que soit la cause | Services critiques |
on-failure | Redémarrage seulement en cas d’erreur | Conteneurs de tâches |
unless-stopped | Toujours redémarrer sauf arrêt manuel | Choix production |
Production : unless-stopped
restart: unless-stopped
Pourquoi unless-stopped plutôt que always ?
La différence : comportement après un docker stop manuel.
always: après arrêt manuel, redémarrage auto si le serveur ou Docker redémarreunless-stopped: arrêt manuel = reste arrêté
Imaginez : vous stoppez un conteneur pour maintenance, le serveur redémarre et il repart tout seul. Frustrant.
Limite de tentatives avec on-failure
on-failure accepte un nombre max. de redémarrages :
restart: on-failure:5 # max. 5 redémarrages
Après 5 échecs consécutifs au démarrage, Docker abandonne. Utile quand un crash en boucle vient d’une cause externe (base injoignable, mauvaise config) — évite la boucle infinie.
Comment choisir ? En bref
- Services critiques (Web, API, base de données) :
unless-stopped - Tâches de fond, scripts planifiés :
on-failure - Dev, exécution temporaire :
no
Piège : la politique de redémarrage ne gère que « faut-il redémarrer après sortie du conteneur ». Pas « le service est-il vraiment utilisable ». Pour ça, il faut le healthcheck.
3. Limites de ressources (deploy.resources) : éviter les débordements
Vous avez déjà vu un conteneur fuiter en mémoire, tout avaler, et l’OOM Killer tuer les autres conteneurs ?
Moi oui. Pas glorieux.
Les limites de ressources posent un plafond par conteneur : dépassement, kill — les autres services sont protégés.
limits vs reservations
deploy:
resources:
limits:
cpus: '1.0' # max. 1 CPU
memory: 512M # max. 512 Mo RAM
reservations:
cpus: '0.5' # min. 0,5 CPU réservé
memory: 256M # min. 256 Mo garanti
- limits : limite dure, dépassement = OOM
- reservations : limite souple, minimum garanti au planificateur
En clair : limits = « ne pas dépasser », reservations = « garantir au minimum ».
Comment régler la limite CPU ?
cpus: '1.0' # max. 1 cœur CPU
cpus: '0.5' # max. 50 % d'un CPU
cpus: '2.0' # max. 2 cœurs
La limite CPU est souple : dépassement = throttling, pas de kill. Mieux vaut viser un peu haut.
Comment régler la limite mémoire ?
memory: 512M # 512 Mo
memory: 2G # 2 Go
La limite mémoire est dure. Dépassement = OOM Killer, sans négociation.
Mes repères :
- Application Node.js : au moins
512M,1Gen production - Application Python :
256M - 512M - PostgreSQL :
1G - 4Gselon connexions et volume - Redis :
256M - 512M, plus si gros cache
Configuration concrète
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
L’app peut utiliser au max. 1 CPU et 1 Go RAM ; Docker garantit au minimum 0,25 CPU et 256 Mo.
Note : deploy vise surtout Docker Swarm. En mono-serveur avec docker-compose up, les limites s’appliquent avec Docker Compose V2 ou docker-compose --compatibility. Alternative historique : mem_limit et cpus (dépréciés) ; deploy est supporté depuis Compose V2.20+.
4. Modèle complet : YAML production prêt à copier
Chaque pilier seul aide ; ensemble, c’est du niveau production. Exemple complet Web + PostgreSQL + Redis, à adapter.
Exemple complet
version: '3.8'
services:
# Application Web
app:
image: myapp:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
logging:
driver: json-file
options:
max-size: "10m" # 10 Mo max. par fichier de log
max-file: "3" # 3 fichiers de log conservés
# Base PostgreSQL
db:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: apppassword
POSTGRES_DB: appdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
volumes:
- pgdata:/var/lib/postgresql/data
# Cache Redis
redis:
image: redis:7-alpine
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
memory: 128M
volumes:
pgdata:
Séparation des configurations
Dev et production diffèrent souvent. Deux fichiers :
# compose.yaml - environnement de développement
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
restart: "no" # pas de redémarrage auto en dev
# compose.production.yaml - surcharge production
version: '3.8'
services:
app:
image: myapp:v1.2.3 # image buildée en production
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
memory: 1G
Lancement production :
docker-compose -f compose.yaml -f compose.production.yaml up -d
Les fichiers fusionnent ; compose.production.yaml écrase compose.yaml.
Logs : éviter de saturer le disque
Le driver par défaut json-file fait croître les logs sans limite. Sans plafond, le disque est plein en quelques mois.
logging:
driver: json-file
options:
max-size: "10m" # 10 Mo max. par fichier
max-file: "3" # 3 fichiers, 30 Mo max. au total
30 Mo de logs max. par conteneur, rotation auto. Je mets ça sur chaque service pour ne pas nettoyer à la main plus tard.
Résumé
En synthèse, la logique des trois piliers :
Healthcheck détecte → redémarrage répare → limites empêchent la propagation
Avec ce trio, votre stack Docker Compose peut :
- Attendre que les dépendances soient prêtes au démarrage, au lieu de foncer tête baissée
- Se relever seule après un crash, sans vous réveiller la nuit
- Empêcher qu’un conteneur déréglé ne fasse tomber tout le serveur
Allez vérifier votre docker-compose.yml. Il manque quoi ? Complétez.
Si vous n’avez pas encore déployé Docker Compose en production, emportez ces trois configs au prochain déploiement. Vous vous remercierez.
Configurer les trois piliers du déploiement Docker Compose en production
Ajouter healthcheck, politique de redémarrage et limites de ressources à Docker Compose pour un déploiement stable en production
⏱️ Estimated time: 15 min
- 1
Step 1: Ajouter la configuration healthcheck
Ajoutez healthcheck à chaque service :
• test : commande de vérification (curl, pg_isready, redis-cli ping, etc.)
• interval : intervalle entre les vérifications (10-30 s recommandé)
• timeout : délai d'expiration (5-10 s recommandé)
• retries : nombre d'échecs avant unhealthy (3-5 recommandé)
• start_period : période de grâce au démarrage (30-60 s selon le temps de boot) - 2
Step 2: Configurer le démarrage conditionnel des dépendances
Utilisez le paramètre condition de depends_on :
• Remplacez depends_on: [db] par depends_on: db: condition: service_healthy
• Assurez-vous que le healthcheck est configuré sur les services dépendants
• L'application attend que les dépendances soient réellement disponibles avant de démarrer - 3
Step 3: Définir la politique de redémarrage
Choisissez la politique selon le type de service :
• Services critiques (Web/API/base de données) : restart: unless-stopped
• Tâches de fond / scripts planifiés : restart: on-failure:5
• Développement / débogage : restart: "no"
• Évitez always (redémarrage inattendu après un arrêt manuel) - 4
Step 4: Configurer les limites de ressources
Définissez limits et reservations dans deploy.resources :
• limits : limite dure, dépassement = OOM Killer
• reservations : limite souple, minimum garanti par Docker
• Application Node.js : limits.memory d'au moins 512M
• Base de données : 1G-4G selon connexions et volume de données - 5
Step 5: Ajouter la rotation des logs
Évitez que les logs saturent le disque :
• logging.driver: json-file (driver par défaut)
• logging.options.max-size: "10m" (10 Mo max. par fichier)
• logging.options.max-file: "3" (3 fichiers conservés)
• Plafond total 30 Mo, rotation automatique
FAQ
Un échec de healthcheck redémarre-t-il automatiquement le conteneur ?
Quelle différence entre unless-stopped et always ?
Quelle différence entre limits et reservations dans les limites de ressources ?
À quoi sert le paramètre start_period ?
Comment utiliser des configurations différentes en dev et en production ?
• compose.yaml : configuration dev (build: ., restart: "no")
• compose.production.yaml : surcharge production (image: xxx, restart: unless-stopped)
• Commande : docker-compose -f compose.yaml -f compose.production.yaml up -d
• Le second fichier écrase le premier, séparation des configs
Peut-on utiliser deploy.resources en déploiement mono-serveur ?
7 min de lecture · Publié le: 24 avr. 2026 · Mis à jour le: 27 juil. 2026
Guide pratique Docker
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Déploiement Docker Compose en production : healthcheck, redémarrage et journaux
Guide pratique Docker Compose en production : configuration du healthcheck, politique de redémarrage et gestion des journaux. De la mort apparente du conteneur à la récupération automatique, sans saturer le disque.
Partie 11 sur 38
Suivant
Déployer un environnement PHP avec Docker Compose : tutoriel DNMP complet (Nginx+MySQL+PHP)
Guide pas à pas pour déployer DNMP (Docker+Nginx+MySQL+PHP) en un clic avec Docker Compose en 10 minutes, éliminer les écarts d'environnement en équipe, avec fichiers de configuration complets et guide de dépannage
Partie 13 sur 38



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire