🎯 Objectif : À la fin de ce chapitre, tu sauras configurer les health checks, centraliser les logs et sécuriser tes conteneurs pour la production. ⏱️ Durée estimée : 50 minutes | Niveau : Avancé
Ton conteneur tourne. docker ps affiche “Up 3 hours”. Tout va bien ? Pas forcément. L’application à l’intérieur peut être plantée, les logs peuvent remplir ton disque en silence, et ton process tourne peut-être en root sans que tu le saches.
En dev, on s’en fiche. En production, chacun de ces points peut transformer un dimanche tranquille en nuit blanche. Ce chapitre t’apprend à passer d’un conteneur qui “tourne” à un conteneur qui tourne bien — avec des health checks qui détectent les vrais problèmes, des logs maîtrisés et des bases de sécurité solides.
Pourquoi c’est important
Un conteneur Docker en production sans health check, c’est comme une voiture sans tableau de bord : tu roules, mais tu ne sais pas si le moteur surchauffe. Le jour où ça casse, tu l’apprends par tes utilisateurs.
🔥 Cas réel : Une startup SaaS avait 12 conteneurs en production. Un mardi, l’API principale a crashé silencieusement — le process Node.js avait paniqué sur une erreur mémoire, mais le conteneur restait “Up” parce que le PID 1 (tini) tournait toujours. Résultat : 45 minutes de downtime avant qu’un développeur remarque les plaintes sur Slack. Un simple health check aurait détecté le problème en 30 secondes.
Les trois piliers d’un conteneur production-ready :
- Health checks — savoir si l’application fonctionne vraiment
- Logs structurés — pouvoir diagnostiquer un problème à 3h du matin
- Sécurité de base — ne pas laisser de portes ouvertes
Comprendre le concept
Health checks
Un health check, c’est une commande que Docker exécute régulièrement dans ton conteneur pour vérifier que l’application répond. Si elle échoue plusieurs fois, le conteneur passe en état unhealthy. Docker gère trois états de santé : starting (démarrage en cours), healthy (tout va bien) et unhealthy (l’application ne répond plus).
L’orchestrateur (Compose, Swarm, Kubernetes) peut alors décider de redémarrer le conteneur ou de le retirer du load balancer. Tu définis un health check soit dans le Dockerfile, soit dans le docker-compose.yml, avec quatre paramètres : l’intervalle entre les vérifications, le timeout, le nombre de retries et le délai de grâce au démarrage.
Logging
Par défaut, Docker capture tout ce que ton application écrit sur stdout et stderr, et le stocke en JSON sur le disque. Sans configuration, ces fichiers grossissent sans limite jusqu’à remplir ta partition. En production, tu veux deux choses : une rotation automatique (pour ne pas exploser le disque) et des logs structurés (pour pouvoir chercher efficacement).
💡 Tip DevOps : Configure toujours la rotation des logs au niveau du daemon Docker (/etc/docker/daemon.json), pas conteneur par conteneur. Un seul conteneur oublié peut remplir ton disque en quelques jours.
Sécurité de base
Par défaut, le process dans un conteneur tourne en root. Si un attaquant s’échappe du conteneur, il hérite de ces droits sur l’hôte. La solution : un USER non-root dans le Dockerfile, no-new-privileges dans Compose, et un filesystem en lecture seule. Deux lignes qui changent tout en cas de compromission.
Commandes essentielles
Voici un Dockerfile production-ready qui combine health check, utilisateur non-root et bonnes pratiques. Le HEALTHCHECK vérifie toutes les 30 secondes que l’endpoint /health répond, avec un délai de grâce de 15 secondes au démarrage :
FROM node:22-alpine
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --chown=app:app package*.json ./
RUN npm ci --omit=dev
COPY --chown=app:app . .
USER app
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget --spider -q http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["node", "server.js"]
Pour vérifier l’état de santé et monitorer les ressources, ces commandes te donnent une vue complète de tes conteneurs en cours d’exécution :
# État du health check
docker inspect --format='{{.State.Health.Status}}' mon-api
# Historique des derniers checks
docker inspect --format='{{json .State.Health}}' mon-api | jq '.Log[-3:]'
# Ressources et santé en temps réel
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
docker ps --format "table {{.Names}}\t{{.Status}}"
La configuration globale des logs se fait dans /etc/docker/daemon.json. Ce fichier applique la rotation à tous les conteneurs, même ceux lancés sans options de log :
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "5",
"tag": "{{.Name}}"
}
}
⚠️ Attention : Après avoir modifié daemon.json, tu dois redémarrer Docker avec sudo systemctl restart docker. Ça redémarre tous les conteneurs qui n’ont pas restart: always. Planifie ça en fenêtre de maintenance.
Cas concret : API e-commerce en production
Tu déploies une API e-commerce avec PostgreSQL et Redis. Voici un docker-compose.yml production-ready qui combine health checks, limites de ressources, sécurité et gestion des secrets :
services:
api:
image: mon-ecommerce:latest
deploy:
resources:
limits:
cpus: "1.5"
memory: 512M
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
postgres:
image: postgres:16-alpine
deploy:
resources:
limits:
memory: 1G
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 10s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
deploy:
resources:
limits:
memory: 256M
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
secrets:
db_password:
file: ./secrets/db_password.txt
volumes:
pgdata:
Points clés de cette configuration :
- L’API attend que PostgreSQL et Redis soient
healthyavant de démarrer (condition: service_healthy) - Les limites mémoire empêchent un conteneur de tuer les autres en cas de fuite
- Le mot de passe utilise un secret monté dans
/run/secrets/plutôt qu’une variable d’environnement visible dansdocker inspect - Le filesystem est en lecture seule avec un
tmpfspour les fichiers temporaires no-new-privilegesbloque toute escalade de privilèges
🧠 À retenir : depends_on sans condition: service_healthy ne vérifie que si le conteneur est démarré, pas si le service est prêt. PostgreSQL peut mettre plusieurs secondes à initialiser sa base — sans cette condition, ton API crashe au démarrage.
Pièges fréquents
Le health check qui ment. Vérifier que le port est ouvert (nc -z localhost 3000) ne prouve rien — ton app peut écouter sur le port sans traiter de requêtes. Teste toujours un endpoint applicatif comme /health qui vérifie aussi la connexion à la base de données.
Les logs qui remplissent le disque. Sans rotation configurée, un conteneur actif génère des Go de logs en quelques jours. Vérifie l’espace utilisé avec du -sh /var/lib/docker/containers/*/. La configuration dans daemon.json est ta première ligne de défense.
⚠️ Attention : Ne confonds pas --memory-swap et --memory. Si tu mets --memory=512m sans toucher au swap, Docker autorise 512 Mo de RAM plus 512 Mo de swap, soit 1 Go au total. Pour désactiver le swap, mets --memory-swap=512m (identique à --memory).
Les secrets en variables d’environnement. docker inspect affiche toutes les variables d’environnement en clair. Utilise les Docker secrets (montés dans /run/secrets/) pour tout ce qui est sensible. Les images officielles PostgreSQL, MySQL et MariaDB supportent nativement les variables *_FILE.
Le depends_on naïf. Sans condition: service_healthy, ton API démarre dès que le conteneur PostgreSQL est lancé — pas quand la base est prête. Résultat : des erreurs “connection refused” au démarrage.
💡 Tip DevOps : Crée un script healthcheck.sh dans ton image plutôt qu’une commande inline. Tu peux y vérifier la connexion à la DB, l’espace disque et la réponse de l’API en un seul check — bien plus robuste qu’un simple curl.
Exercice pratique
Lance un conteneur Nginx production-ready avec health check, limites de ressources et rotation des logs :
docker run -d \
--name nginx-prod \
--memory=128m \
--cpus=0.5 \
--log-opt max-size=10m \
--log-opt max-file=3 \
--health-cmd="curl -f http://localhost/ || exit 1" \
--health-interval=10s \
--health-retries=3 \
nginx:alpine
Ensuite, vérifie que tout est en place :
docker ps— observe le statut passer de(health: starting)à(healthy)docker stats --no-stream— confirme la limite mémoire à 128 Modocker inspect --format='{{.State.Health.Status}}' nginx-prod— doit afficherhealthy- Simule une panne :
docker exec nginx-prod nginx -s stopet observe le passage enunhealthy docker logs nginx-prod— vérifie que les logs sont bien capturés
🧠 À retenir :
- Health checks : vérifie un endpoint applicatif, pas juste un port ouvert
- Logs : rotation dans
daemon.json, pas conteneur par conteneur - Sécurité :
USERnon-root +no-new-privileges+read_only - Ressources : limites mémoire sur tous les conteneurs, sans exception
- Secrets :
/run/secrets/plutôt que des variables d’environnement - Dépendances :
depends_onaveccondition: service_healthy, toujours
🔥 Cas réel : Les équipes SRE estiment que 60% des incidents Docker en production viennent de trois causes : pas de health check (incident non détecté), pas de limite mémoire (un conteneur tue les autres), et pas de rotation de logs (disque plein). Ce chapitre couvre les trois.
➡️ La suite : Dans le prochain chapitre, on aborde le scanning de vulnérabilités, le monitoring et les best practices de déploiement. On continue ! 🚀
🖥️ Pratique sur ton propre serveur
Pour suivre Apprendre Docker en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Apprendre Docker
7 / 10- Pourquoi Docker ? Les conteneurs expliqués
- Tes premières commandes Docker
- Ton premier Dockerfile
- Dockerfile avancé : multi-stage et optimisation
- Docker Compose : orchestrer tes services
- Compose avancé : volumes, réseaux et scaling
- 7 Docker en production : logs et healthchecks
- 8 Déploiement et CI/CD avec Docker
- 9 Sécurité Docker : rootless et isolation
- 10 Scanning et conformité Docker
Sur cette page
Articles liés
Pourquoi Docker ? Les conteneurs expliqués
Découvre ce que sont les conteneurs, comment ils se distinguent des machines virtuelles et comprends l'architecture Docker.
Tes premières commandes Docker
Prends en main Docker avec tes premières commandes : docker run, pull, ps, images, exec et le cycle de vie des conteneurs.
Ton premier Dockerfile
Apprends à écrire un Dockerfile avec les instructions essentielles : FROM, COPY, RUN, CMD et docker build.