Aller au contenu

Health checks

Signaler l'état de sante des services à l'orchestrateur — liveness, readiness, startup et stratégies de déploiement.


Trois types, trois rôles

Les health checks permettent à l'orchestrateur (Kubernetes, load balancer) de savoir si un service peut recevoir du trafic. Il existe trois types avec des rôles très différents — les confondre crée des comportements contre-intuitifs et dangereux.

Type Question posee Exemple de check Action si échec
Liveness Le processus est-il vivant ? Répondre 200 sur /healthz Redémarrer le conteneur
Readiness Le service peut-il traiter des requêtes ? Vérifier DB + cache accessibles Retirer du load balancer
Startup Le service a-t-il fini de démarrer ? Migrations terminees, warm-up effectue Attendre avant d'activer liveness/readiness

Liveness

Détecté un processus bloque (deadlock, OOM, boucle infinie). Le check doit être minimal — une simple réponse HTTP 200 sur /healthz. Kubernetes redemarrera le pod si ce check échoué repetitivement.

Le liveness ne doit PAS vérifier les dépendances externes. Si la base de données est lente, le processus est vivant — il ne faut pas le redémarrer. Le redémarrage creerait une boucle : le pod redemarrerait, tenterait de se reconnecter a une DB déjà saturee, echouerait au liveness, serait redémarrer à nouveau.

Readiness

Détecté un service temporairement incapable de traiter des requêtes. La DB est en maintenance, le cache est en cours de warm-up, une migration est en cours. Le pod reste vivant mais sort de la rotation du load balancer.

Le readiness peut vérifier les dépendances critiques. Il répond à la question : "si je recois une requête maintenant, est-ce que je suis capable de la traiter correctement ?"

Startup

Désactivé liveness et readiness pendant le démarrage pour éviter de tuer un pod qui n'a pas encore eu le temps de s'initialiser. Utile pour les services avec des démarrages longs :

  • Chargement de modèles ML (parfois plusieurs minutes)
  • Migrations de schéma de base de données
  • Precalcul de cache ou warm-up d'index
  • Téléchargement de fichiers de configuration volumineux

Deep vs shallow

La profondeur du health check détermine ce qu'il vérifié et les risques associes.

Shallow — le processus répond. Rapide (< 5ms), peu coûteux. Utilisé pour le liveness. Ne vérifié que l'état interne du process.

// GET /healthz — shallow
{
  "status": "ok",
  "uptime": 3600
}

Deep — les dépendances critiques sont aussi accessibles. Vérifié que la DB répond en moins de X ms, que le cache est joignable, que les APIs externes clés sont disponibles. Réservé au readiness.

// GET /ready — deep
{
  "status": "ok",
  "checks": {
    "database": {"status": "ok", "latency_ms": 12},
    "redis": {"status": "ok", "latency_ms": 3},
    "payment-api": {"status": "ok", "latency_ms": 45}
  }
}

Tip

Les liveness checks doivent être shallow. Un check deep qui inclut la DB fera redémarrer votre service quand la DB est lente, aggravant la situation. La distinction est simple : Liveness = le processus respire. Readiness = le processus est prêt à travailler.

Checklist des dépendances a inclure dans le readiness

Dépendance Inclure ? Justification
Base de données Oui Sans DB, le service ne peut pas traiter les requêtes
Cache (Redis) Depends Oui si critique pour la performance, non si fallback local
API externe critique Oui Si le service ne peut pas fonctionner sans
API externe secondaire Non Le service peut fonctionner en mode dégradé
File system local Rarement Sauf si le service écrit des fichiers critiques
Message broker Oui Si le service est un consumer Kafka/RabbitMQ

Configuration Kubernetes

apiVersion: v1
kind: Pod
spec:
  containers:
    - name: api
      image: api:1.2.0
      ports:
        - containerPort: 8080
      startupProbe:
        httpGet:
          path: /healthz
          port: 8080
        failureThreshold: 30
        periodSeconds: 2
        # Le pod a 60s pour demarrer (30 * 2s)
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 0
        periodSeconds: 10
        failureThreshold: 3
        timeoutSeconds: 2
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 0
        periodSeconds: 5
        failureThreshold: 3
        successThreshold: 1
        timeoutSeconds: 3

Parametres critiques

Parametre Liveness recommande Readiness recommande Explication
periodSeconds 10s 5s Readiness doit reagir plus vite
failureThreshold 3 3 3 échecs consecutifs avant action
timeoutSeconds 2s 3s Readiness peut tolérer un peu plus (deep check)
successThreshold 1 1 1 succès suffit pour revenir en rotation

Graceful shutdown

Le health check ne suffit pas si le service ne sait pas s'arrêter proprement. Quand Kubernetes envoie un signal SIGTERM, le service doit :

  1. Cesser d'accepter de nouvelles requêtes — le readiness doit retourner un échec immédiatement
  2. Terminer les requêtes en cours — laisser les requêtes actives se terminer normalement
  3. Fermer les connexions proprement — libérer les connexions DB, fermer les consumers Kafka, flusher les buffers
  4. S'arrêter — quitter le processus avec un code 0
sequenceDiagram
    participant K as Kubernetes
    participant LB as Load Balancer
    participant P as Pod
    participant R as Requetes en cours

    K->>P: SIGTERM
    P->>P: readiness = false
    K->>LB: Retirer du endpoint
    Note over LB: Nouveau trafic\nvers autres pods
    P->>R: Terminer requetes en cours
    R-->>P: Toutes terminees
    P->>P: Fermer connexions
    P->>K: Exit 0

    Note over K: Si timeout (30s par defaut)\nSIGKILL force

Le terminationGracePeriodSeconds (défaut 30s) est le délai maximal entre SIGTERM et SIGKILL. Si le service n'a pas termine en 30 secondes, Kubernetes le tue de force. Ajuster cette valeur pour les services avec des traitements longs.


Readiness gates et déploiement

Readiness gates

Les readiness gates sont des conditions supplémentaires que Kubernetes vérifié avant de considérer un pod comme "ready". Elles sont utiles quand le readiness probe standard ne suffit pas :

  • Le service doit être enregistre dans un service mesh avant de recevoir du trafic
  • Un warm-up externe est nécessaire (precharger un CDN, invalider un cache)
  • Une vérification humaine est requise (pour les déploiements critiques)
apiVersion: v1
kind: Pod
spec:
  readinessGates:
    - conditionType: "custom.io/mesh-registered"
    - conditionType: "custom.io/cache-warm"

Le pod ne recevra du trafic que quand toutes les conditions de readiness (probes + gates) sont satisfaites.


Stratégies de déploiement et health checks

Les health checks sont le pilier de toute stratégie de déploiement progressive. Sans eux, l'orchestrateur n'a aucun moyen de savoir si la nouvelle version fonctionne.

Rolling update

Déployer les nouveaux pods un par un. Chaque nouveau pod doit passer son readiness probe avant que le suivant soit déployé et qu'un ancien pod soit arrêté.

graph LR
    subgraph Etape1["Etape 1"]
        V1a["v1"] 
        V1b["v1"]
        V1c["v1"]
    end
    subgraph Etape2["Etape 2"]
        V1d["v1"]
        V1e["v1"]
        V2a["v2 — readiness OK"]
    end
    subgraph Etape3["Etape 3"]
        V1f["v1"]
        V2b["v2"]
        V2c["v2"]
    end

    Etape1 -->|deploy| Etape2
    Etape2 -->|readiness OK| Etape3

    style V2a fill:#2a9d8f,color:#fff
    style V2b fill:#2a9d8f,color:#fff
    style V2c fill:#2a9d8f,color:#fff

Configuration Kubernetes :

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1        # 1 pod supplementaire pendant le deploiement
    maxUnavailable: 0  # 0 pod indisponible — zero downtime

maxUnavailable: 0 garantit qu'aucun ancien pod n'est retire tant que le nouveau n'est pas ready. C'est le reglage le plus conservateur — plus lent mais sans perte de capacité.

Blue-green

Deux environnements complets existent en parallèle. Le trafic est bascule integralement de l'ancien (blue) vers le nouveau (green) quand tous les health checks du green sont valides.

Aspect Rolling update Blue-green
Rollback Lent (re-déployer) Instantané (rebascule)
Ressources N + 1 pods 2N pods
Risque Versions mixtes Tout ou rien
Health check rôle Par pod progressif Validation globale avant switch

Canary

Envoyer un pourcentage faible du trafic (1-5%) vers la nouvelle version. Monitorer les métriques (latence, erreurs, SLI). Si les health checks et les métriques sont bons, augmenter progressivement le pourcentage.

graph LR
    LB["Load Balancer"]
    LB -->|95%| V1["v1 — 3 pods"]
    LB -->|5%| V2["v2 — 1 pod canary"]

    V2 -->|metriques| Mon["Monitoring"]
    Mon -->|OK| Inc["Augmenter %"]
    Mon -->|KO| Roll["Rollback"]

    style V2 fill:#e9c46a,color:#000

Le canary est la stratégie la plus sure pour les services a fort trafic. L'impact d'un bug est limite a 5% des utilisateurs, et le rollback est immédiat.

Matrice de choix

Critère Rolling Blue-green Canary
Vitesse de rollback Lente Instantanée Instantanée
Coût en ressources Faible Double Faible
Détection de régression Tardive Pre-switch Progressive
Complexité Faible Moyenne Élevée
Convient pour Standard Critique Fort trafic

Warning

Un déploiement canary sans health checks et sans métriques automatisees est un déploiement à l'aveugle avec un nom elegant. Le canary n'a de valeur que si on compare activement les SLI de la version canary avec ceux de la version stable. Sans cette comparaison, on ne détecté rien.


Chapitre suivant : SLI, SLO, SLA — mesurer et formaliser la fiabilité.