infra / docker
Healthchecks
Explication
Ce que vous allez apprendre
- Comprendre pourquoi un conteneur "en cours d'exécution" n'est pas nécessairement fonctionnel
- Déclarer un healthcheck dans un Dockerfile avec les bonnes options (
interval,timeout,start-period,retries) - Comprendre le rôle du
start_periodpour éviter les faux négatifs au démarrage - Écrire un endpoint
/healthqui vérifie réellement les dépendances critiques, pas juste "ok" - Comprendre comment un état "unhealthy" est exploité par
depends_onou un orchestrateur
Dans quel contexte ?
Une API perd sa connexion à la base de données suite à un problème réseau temporaire, mais le processus principal continue de tourner sans planter — il répond simplement des erreurs 500 à toutes les requêtes. Sans healthcheck, docker ps continue d'afficher le conteneur comme normal, masquant complètement l'incident. Avec un endpoint /health qui teste réellement la connexion à la base, Docker détecte le problème en quelques secondes et peut déclencher un remplacement automatique du conteneur défaillant.
"Tourner" n'est pas la même chose que "fonctionner"
Un conteneur peut apparaître comme "en cours d'exécution" (docker ps le montre bien démarré) tout en étant totalement incapable de répondre correctement à une requête — un processus bloqué, une connexion à la base de données perdue, une fuite mémoire qui a rendu l'application inutilisable sans pour autant la faire planter. Le simple fait que le processus principal tourne ne garantit donc rien sur la santé réelle de l'application. C'est précisément le problème que résout le healthcheck.
| Option | Rôle |
|---|---|
--interval | Fréquence de vérification |
--timeout | Délai max avant d'échouer le check |
--start-period | Délai de grâce au démarrage |
--retries | Échecs consécutifs avant de marquer "unhealthy" |
Piège fréquent
Un endpoint /health qui se contente de répondre "ok" sans rien vérifier n'a presque aucune valeur : il indique seulement que le serveur web répond, pas que l'application peut réellement fonctionner. Teste toujours au moins une dépendance critique (base de données, cache) dans ton endpoint de santé.
Le principe
Un healthcheck est une commande que Docker exécute à intervalle régulier, à l'intérieur du conteneur, pour vérifier que l'application répond correctement — le plus souvent en interrogeant un point d'accès dédié comme /health. Selon le résultat, Docker qualifie le conteneur de "healthy" (sain) ou "unhealthy" (défaillant), un état visible dans docker ps et interrogeable par un script ou un orchestrateur.
Le rôle de start_period
Beaucoup d'applications ont besoin de quelques secondes après leur lancement avant d'être réellement opérationnelles (chargement de configuration, connexion initiale à une base). Sans délai de grâce, le healthcheck échouerait à tort dès les premières secondes. start_period (ou --start-period) accorde ce délai avant de commencer à compter les échecs, évitant des faux positifs au démarrage.
Ce qu'un bon /health doit réellement vérifier
Un endpoint de santé qui se contente de répondre "ok" sans rien vérifier n'a presque aucune valeur : il indique seulement que le serveur web répond, pas que l'application peut réellement fonctionner. Un bon healthcheck teste les dépendances critiques (une requête simple vers la base de données, par exemple), pour détecter les pannes qui comptent vraiment.
Important à retenir
Un conteneur "unhealthy" ne s'arrête PAS tout seul : le healthcheck n'est qu'un signal, exploité ensuite par depends_on: condition: service_healthy (vu en Compose) ou par un orchestrateur pour décider de remplacer automatiquement le conteneur défaillant.
Commandes & code
Healthchecks
# Healthcheck directement dans le Dockerfile
FROM python:3.12-slim
# ...
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD curl -fsS http://localhost:8000/health || exit 1
# --interval : fréquence de vérification
# --timeout : délai max avant de considérer le check comme échoué
# --start-period : délai de grâce au démarrage (l'appli met du temps à être prête)
# --retries : nombre d'échecs consécutifs avant de marquer le conteneur "unhealthy"docker ps # colonne STATUS affiche "(healthy)" ou "(unhealthy)"
docker inspect --format '{{.State.Health.Status}}' mon-api
docker inspect --format '{{json .State.Health}}' mon-api | python3 -m json.tool # historique des checks# Healthcheck dans docker-compose.yml (souvent préféré au Dockerfile pour rester flexible par environnement)
services:
api:
build: .
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"]
interval: 15s
timeout: 3s
retries: 3
start_period: 10s
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 5# Endpoint /health minimal côté application (FastAPI) : vérifie AUSSI ses dépendances critiques
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/health")
def health():
try:
db.execute("SELECT 1") # un /health qui ne vérifie rien n'a quasiment aucune valeur
except Exception:
return Response(status_code=503)
return {"status": "ok"}# Un conteneur "unhealthy" ne s'arrête PAS automatiquement : le healthcheck sert de signal
# pour un orchestrateur (Swarm, Kubernetes) ou pour un "depends_on: condition: service_healthy"
docker events --filter event=health_status # observe les changements d'état en temps réel
# Combiner avec un restart policy pour une auto-remédiation basique
docker run -d --health-cmd="curl -f http://localhost:8000/health || exit 1" \
--restart unless-stopped mon-api:1.0Résumé
- Un healthcheck se déclare dans le Dockerfile ou dans compose ;
start_periodévite les faux négatifs au démarrage. docker ps/docker inspectexposent l'état (healthy/unhealthy), consommé pardepends_onou un orchestrateur.- Un bon
/healthvérifie les dépendances critiques (base de données, cache), pas seulement que le process répond.
Exercices pratiques
Mission : détecter une API en panne que docker ps déclare pourtant saine
Objectif : Corriger un healthcheck superficiel et régler ses paramètres pour éviter les faux positifs au démarrage.
Contexte
Une API a perdu sa connexion à la base de données mais continue de tourner et répond des erreurs 500. Son endpoint /health actuel se contente de répondre "ok" sans rien vérifier, donc docker ps l'affiche toujours comme saine.