Wat elk probetype doet en wanneer het afgaat
Drie probes, drie verschillende gevolgen bij falen. Dit door elkaar halen is de hoofdoorzaak van de meeste probe-gerelateerde incidenten.
Liveness probe. Draait continu op periodSeconds-interval. Als de probe failureThreshold keer achter elkaar faalt, herstart de kubelet de container (niet de pod; het pod-object blijft bestaan). Gebruik dit om te herstellen van deadlocks of vastgelopen processen die nooit vanzelf herstellen.
Readiness probe. Draait ook continu, niet alleen bij opstarten. Bij falen verwijdert de kubelet de pod uit alle bijbehorende Service-endpoints. De container blijft draaien. Verkeer stopt met binnenkomen. Zodra de probe weer slaagt, wordt de pod opnieuw toegevoegd. Gebruik dit om aan te geven dat een container tijdelijk geen requests kan verwerken.
Startup probe. Draait eenmalig bij het starten van de container. Blokkeert liveness- en readiness-probes totdat hij slaagt. Als hij failureThreshold keer achter elkaar faalt, herstart de kubelet de container. Zodra hij slaagt, draait hij nooit meer. Gebruik dit voor containers met trage of wisselende opstarttijden.
| Probe | Actie bij falen | Wanneer | Blokkeert andere probes? |
|---|---|---|---|
| Startup | Container herstart (na threshold) | Eenmalig bij opstarten | Ja |
| Liveness | Container herstart (na threshold) | Continu | Nee |
| Readiness | Pod verwijderd uit endpoints | Continu | Nee |
Een veelvoorkomend misverstand: readiness-probes zijn geen opstart-mechanisme. Ze draaien gedurende de volledige levensduur van de pod. Een pod die vijf minuten geleden ready was, kan op elk moment not-ready worden als de probe begint te falen.
De vier probemechanismen
Elk probetype ondersteunt vier mechanismen. Kies het mechanisme dat past bij de interface van je service.
HTTP-probe (httpGet)
De kubelet stuurt een HTTP GET-request. Statuscodes 200 tot en met 399 tellen als succes. Alles anders is een fout.
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders: # optioneel; kubelet stuurt standaard User-Agent: kube-probe
- name: X-Custom
value: probe
periodSeconds: 10
failureThreshold: 3
Meest geschikt voor: elke service die HTTP aanbiedt. Veruit de meest gebruikte keuze.
TCP-probe (tcpSocket)
De kubelet probeert een TCP-connectie te openen. Succes betekent dat de verbinding tot stand kwam. Het verifieert niet of de applicatie daadwerkelijk requests verwerkt.
readinessProbe:
tcpSocket:
port: 5432
periodSeconds: 10
failureThreshold: 3
Meest geschikt voor: databases, message brokers en andere TCP-services die geen HTTP aanbieden.
Exec-probe (exec)
De kubelet voert een commando uit in de container. Exit code 0 is succes; alles anders is een fout.
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
periodSeconds: 10
failureThreshold: 3
Bekend probleem: exec-probes starten een child-proces per uitvoering. Als PID 1 in je container geen init-systeem is, worden die children zombieprocessen. Bij lage periodSeconds met veel pods raakt de PID-ruimte op de node uitgeput. Gebruik tini of dumb-init als PID 1 als je exec-probes gebruikt.
Meest geschikt voor: custom health-logica die niet als HTTP of TCP uit te drukken is. Geef de voorkeur aan HTTP of TCP waar mogelijk.
gRPC-probe (grpc)
De kubelet roept het gRPC Health Checking Protocol aan (grpc.health.v1.Health/Check). GA sinds Kubernetes 1.27; geen feature gate nodig.
readinessProbe:
grpc:
port: 50051 # moet numeriek zijn; named ports worden niet ondersteund
periodSeconds: 10
failureThreshold: 3
Beperkingen: geen client-certificaatondersteuning, geen TLS-certificaatvalidatie, geen service name chaining.
Meest geschikt voor: gRPC-services die het standaard health checking protocol implementeren.
Timingparameters
Zes parameters bepalen hoe snel probes afgaan, hoe lang ze wachten en hoeveel fouten actie triggeren.
| Parameter | Default | Wat het bepaalt |
|---|---|---|
initialDelaySeconds |
0 | Seconden voor de eerste probe afgaat |
periodSeconds |
10 | Seconden tussen probe-uitvoeringen |
timeoutSeconds |
1 | Seconden dat de kubelet wacht op antwoord |
successThreshold |
1 | Opeenvolgende successen om healthy te markeren |
failureThreshold |
3 | Opeenvolgende fouten voor actie |
terminationGracePeriodSeconds |
Erft van pod-level | Override voor probe-getriggerde restarts (1.25+) |
Defaultwaarden staan in de officiele Kubernetes probe-configuratiereferentie.
Twee beperkingen om te weten:
successThresholdvoor liveness- en startup-probes moet 1 zijn. De API weigert andere waarden.terminationGracePeriodSecondsop probe-level (beschikbaar sinds Kubernetes 1.25) overschrijft de pod-level-waarde. Handig als deadlock-recovery snel moet herstarten, maar een normale shutdown een lang drain-venster nodig heeft.
Startup-probes configureren voor traag opstartende applicaties
Voor de startup-probe bestond, was een grote initialDelaySeconds op de liveness-probe de enige optie voor traag startende containers. Dat creert een vaste wachttijd, ook bij snelle opstart, en past zich niet aan bij wisselende opstarttijden.
De startup-probe lost dit op. Hij blokkeert liveness en readiness totdat de applicatie expliciet aangeeft klaar te zijn. De formule:
failureThreshold x periodSeconds >= worst-case opstarttijd
Een Java-applicatie die tot 3 minuten nodig heeft om te starten:
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 18 # 18 x 10 = 180 seconden = 3 minuten
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 3
Zodra de startup-probe slaagt, draait hij nooit meer. Vanaf dat punt neemt de liveness-probe het over.
Ontwerp je health-endpoints
De belangrijkste regel: controleer nooit externe dependencies in een liveness probe. Als je database uitvalt en elke pod's liveness-probe de databaseverbinding checkt, herstarten alle pods tegelijk. De herstartstorm verergert de outage in plaats van ervan te herstellen.
Aanbevolen endpointpatroon
Scheid je liveness- en readiness-endpoints:
/healthz (liveness): retourneert 200 als de HTTP-loop leeft. Checkt niets extern. Stel het je voor als "is dit proces vastgelopen?" Als het antwoord nee is, retourneer 200.
// Liveness: bewijs dat het proces kan reageren
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
/ready (readiness): retourneert 200 als de applicatie klaar is met initialiseren en kritieke dependencies bereikbaar zijn. Retourneert 503 tijdens opstart, cache-opwarming of dependency-onbereikbaarheid.
// Readiness: verifieer dat de app echte requests kan bedienen
http.HandleFunc("/ready", func(w http.ResponseWriter, r *http.Request) {
if !appReady || !dbPool.Ping() {
w.WriteHeader(http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
})
Wees ook bij readiness voorzichtig met dependency-checks. Zet timeoutSeconds boven de P99-responstijd van de dependency en verhoog failureThreshold boven de standaard 3. Een latencyspike op een gedeelde database mag niet tegelijkertijd elke pod uit elke Service verwijderen.
Veelvoorkomende configuratiefouten
Liveness-probe killt traag opstartende containers
Symptoom: pod gaat direct na deployment in CrashLoopBackOff. kubectl describe pod toont Liveness probe failed-events voordat de applicatie klaar is met opstarten.
Fix: voeg een startup-probe toe met failureThreshold x periodSeconds die de worst-case opstarttijd dekt. Verwijder eventuele grote initialDelaySeconds van de liveness-probe.
Identieke liveness- en readiness-configuratie
Symptoom: onder belasting worden pods tegelijkertijd uit endpoints verwijderd (readiness) en herstart (liveness). Actieve verbindingen vallen weg zonder graceful shutdown.
Fix: geef liveness een hogere failureThreshold dan readiness. Readiness moet de eerste verdedigingslinie zijn (stop verkeer), liveness het laatste redmiddel (herstart).
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
failureThreshold: 3 # verwijderd uit verkeer na 15 seconden
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 6 # herstart na 60 seconden, niet 15
Externe dependency in liveness-probe
Symptoom: een tijdelijke database-outage laat alle pods tegelijk herstarten. Recovery duurt minuten in plaats van seconden.
Fix: verplaats de dependency-check naar de readiness-probe. Houd het liveness-endpoint puur intern.
Verkeerd pad of poort
Symptoom: de probe retourneert een 404 of connection refused vanaf de eerste poging. Pod herstart voordat hij ooit verkeer heeft bediend.
Diagnose:
kubectl exec <pod> -- curl -v http://localhost:8080/healthz
Fix: zorg dat het probe-path en de port overeenkomen met wat de applicatie daadwerkelijk bindt. Check je Dockerfile EXPOSE-directive en de listen-configuratie van je applicatie. Let op: Kubernetes negeert de Docker HEALTHCHECK-directive volledig; die vervangt geen probe-configuratie.
Readiness-timeout korter dan dependency-latency
Symptoom: alle pods worden not-ready tijdens belastingspieken, ook al functioneert de applicatie zelf. Het readiness-endpoint bevraagt een dependency die in 1,2 seconde antwoordt, maar timeoutSeconds is 1 (de standaard).
Fix: zet timeoutSeconds ruim boven de P99-responstijd van wat het readiness-endpoint controleert.
Probes en rolling updates
Zonder readiness-probes markeert Kubernetes een pod als Ready op het moment dat de container start. Tijdens een rolling update betekent dat: de nieuwe pod ontvangt verkeer voordat de applicatie klaar is met initialiseren.
Met readiness-probes wacht de rollout-controller tot elke nieuwe pod zijn readiness-probe haalt voordat er verkeer naartoe gerouteerd wordt. De oude pod wordt pas getermineerd als de nieuwe Ready is.
Voor zero-downtime rolling updates combineer je readiness-probes met deze Deployment-instellingen:
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # verwijder nooit een oude pod tot een nieuwe ready is
maxSurge: 1 # sta een extra pod toe tijdens de transitie
minReadySeconds: 30 # wacht 30 seconden na readiness voordat je verdergaat
minReadySeconds voegt een buffer toe na readiness-succes. Als de nieuwe pod binnen dat venster crasht, pauzeert de rollout in plaats van de volgende oude pod af te breken.
Compleet voorbeeld: alle drie de probes
Een productie-deployment voor een webapplicatie met een worst-case opstarttijd van 90 seconden:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
minReadySeconds: 15
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
terminationGracePeriodSeconds: 60
containers:
- name: web-app
image: registry.internal/web-app:4.2.1
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 10 # 10 x 10 = 100 seconden max opstart-venster
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 6 # herstart na 60 seconden falen
timeoutSeconds: 2
terminationGracePeriodSeconds: 10 # snelle herstart bij deadlock (K8s 1.25+)
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
failureThreshold: 3 # verwijderd uit verkeer na 15 seconden
timeoutSeconds: 3 # ruim voor dependency-checks in /ready
Controleer of je probes werken
Bevestig probe-gedrag na deployment:
# Controleer op probe-gerelateerde events
kubectl describe pod <pod-name> | grep -A 5 "Events:"
# Bekijk pod-statustransities
kubectl get pods -w
# Test het endpoint handmatig vanuit de pod
kubectl exec <pod-name> -- curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/healthz
Gezonde output van kubectl describe pod toont geen Unhealthy-events in het events-gedeelte. Als je Liveness probe failed- of Readiness probe failed-events ziet, check dan het pad, de poort en de timingparameters van de probe tegen het daadwerkelijke gedrag van de applicatie.
Wanneer escaleren
Als probes blijven falen nadat je de configuratie hebt geverifieerd, verzamel dan het volgende voordat je escaleert:
- Output van
kubectl describe pod <pod-name>(volledig, niet afgekapt) - Applicatielogs:
kubectl logs <pod-name> --previous(voor de gecrasht container) - Node-resourcegebruik:
kubectl top nodeenkubectl top pod - De exacte probe-configuratie uit de Deployment-spec
- Kubernetes-versie:
kubectl version - Of de fout consistent of intermitterend is