Hoe Kubernetes probes werken
Wat je zult leren
- De drie typen probes en waar ze voor dienen.
- Hoe je ze configureert en combineert.
- Hoe veelvoorkomende verkeerde configuraties leiden tot fouten.
- Hoe probes de snelheid van een Deployment beïnvloeden.
---
Een pod zonder probes
Stel dat we een pod willen draaien met een enkele container. Hier is het manifest, pod-a.yaml:
apiVersion: "v1"
kind: "Pod"
metadata:
name: "pod-a"
spec:
containers:
- name: "app"
image: "my-app:latest"
De image my-app:latest heeft een paar seconden nodig voor de initialisatie voordat deze gaat luisteren op poort 8080.
Wanneer een container crasht, start Kubernetes deze direct opnieuw. Na de tweede crash legt Kubernetes een CrashLoopBackOff op voordat de container opnieuw wordt gestart. Standaard is deze vertraging 10 seconden, waarbij de wachttijd bij elke crash verdubbelt tot een maximum van 5 minuten.
In beide gevallen beschouwt Kubernetes de container als Ready zodra deze start, ook al is dat niet het geval. De container is dan nog bezig met opstartwerk en luistert nog niet op poort 8080.
Als een client-verzoek (bijvoorbeeld van een ingress controller of load balancer) wordt verzonden op het moment dat de container herstart, zal dat verzoek mislukken. Vanaf het moment dat de container herstart tot het moment dat het opstartwerk is voltooid, falen de requests, ook al wordt de container als 'Ready' beschouwd.
Om dit op te lossen gebruikt Kubernetes probes. Probes zijn periodieke controles die naar containers worden gestuurd om hun gezondheid te bepalen. Er zijn drie varianten:
- Startup probes: bepalen of de applicatie in de container is opgestart.
- Readiness probes: bepalen of de applicatie klaar is om verkeer te ontvangen.
- Liveness probes: bepalen of de applicatie moet worden herstart.
---
Startup probes
Een startup probe kan worden toegevoegd aan pod-a.yaml:
apiVersion: "v1"
kind: "Pod"
metadata:
name: "pod-a"
spec:
containers:
- name: "app"
image: "my-app:latest"
startupProbe:
httpGet:
path: "/startup"
port: 8080
periodSeconds: 1
failureThreshold: 5
Dit is een httpGet probe die een GET /startup verzoek stuurt naar de pod op poort 8080. Statuscodes tussen 200 en 399 worden als succes beschouwd. Dit gebeurt elke periodSeconds seconde, en mag failureThreshold keer achter elkaar mislukken voordat Kubernetes de container doodt. In dit voorbeeld krijgt de container ongeveer 5 seconden om het opstartwerk te voltooien.
Naast httpGet ondersteunt Kubernetes ook tcpSocket, exec en grpc probes. Probes worden verzonden door de kubelet, een proces dat op elke node in het cluster draait en ervoor zorgt dat de juiste pods draaien en worden gecontroleerd.
Integratie met Services en load balancing
Wanneer een container een startup probe heeft, is de status standaard NotReady (technisch gezien is de Ready-conditie False of Unknown).
Om verkeer correct te beheren, is een productie-setup met meerdere kopieën van de pod en een Service voor load balancing nodig.
replica-set-a.yaml:
apiVersion: "apps/v1"
kind: "ReplicaSet"
metadata:
name: "replica-set-a"
spec:
replicas: 2
selector:
matchLabels:
app: "pod-a"
template:
metadata:
labels:
app: "pod-a"
spec:
containers:
- name: "app"
image: "my-app:latest"
startupProbe:
httpGet:
path: "/startup"
port: 8080
periodSeconds: 1
failureThreshold: 5
service-a.yaml:
apiVersion: "v1"
kind: "Service"
metadata:
name: "service-a"
spec:
selector:
app: "pod-a"
ports:
- port: 80
targetPort: 8080
Kubernetes gebruikt de Ready-conditie van een pod om te bepalen of deze wordt opgenomen in de load balancing van de Service. Wanneer een container NotReady is, wordt de hele pod als niet klaar gemarkeerd en ontvangt deze geen verkeer via de Service.
Graceful termination
Om te voorkomen dat requests falen tijdens het verwijderen van een pod, maakt Kubernetes gebruik van een termination grace period (standaard 30 seconden).
Het proces werkt als volgt:
- De kubelet stuurt een
SIGTERMsignaal naar de container. - De pod wordt gemarkeerd als
terminatingen verwijderd uit de Services, waardoor er geen nieuwe requests meer binnenkomen. - De container heeft tijd om lopende requests af te ronden.
- Na de grace period stuurt de kubelet een
SIGKILLals de container nog steeds draait.
De combinatie van graceful termination en startup probes zorgt ervoor dat verkeer wegblijft bij containers die opstarten of stoppen.
Verkeerde configuratie van startup probes
De waarden voor failureThreshold en periodSeconds moeten zorgvuldig worden gekozen. Als de totale tijd (failureThreshold × periodSeconds) te kort is, krijgt de container niet genoeg tijd om op te starten, wat leidt tot een oneindige restart-loop (CrashLoopBackOff). Kies waarden die rekening houden met de slechtst denkbare opstarttijd.
---
Readiness probes
Zodra een startup probe is geslaagd, monitoren readiness probes de container voor de rest van zijn levensduur. Als een readiness probe faalt, wordt de container NotReady en wordt deze uit de Service verwijderd.
Voorbeeld van pod-a.yaml met enkel een readiness probe:
apiVersion: "v1"
kind: "Pod"
metadata:
name: "pod-a"
spec:
containers:
- name: "app"
image: "my-app:latest"
readinessProbe:
httpGet:
path: "/ready"
port: 8080
periodSeconds: 3
failureThreshold: 1
successThreshold: 1
Out-of-band probing
Soms voert Kubernetes readiness probes vaker uit dan de geconfigureerde periodSeconds. Dit gebeurt wanneer een container NotReady is; updates aan de pod (zoals wijzigingen in annotaties of status) kunnen een extra probe triggeren om de pod sneller 'Ready' te maken.
Drempelwaarden
Standaard is successThreshold 1 en failureThreshold 3. Het is aan te raden deze waarden niet te verlagen naar 1, omdat een enkele tijdelijke fout dan direct zou leiden tot het verwijderen van de pod uit de Service.
---
Waarom startup probes nodig zijn naast readiness probes
Men zou kunnen denken dat een readiness probe voldoende is, maar startup probes bieden specifieke voordelen:
- Vertraging: Ze vertragen de start van readiness en liveness probes tot de initialisatie is voltooid.
- Flexibiliteit: Ze staan toe dat de opstartfase vaker wordt gecontroleerd (
periodSeconds) dan de stabiele fase. - Herstel: Herhaalde startup-fouten doden de container en passen het restart-beleid toe, terwijl readiness-fouten dat niet doen. Een restart kan helpen bij een container die "vastzit" tijdens het opstarten.
Je kunt beide combineren: een startup probe die elke seconde controleert voor een snelle detectie, gevolgd door een readiness probe die elke 5 seconden controleert om de belasting op de container en de kubelet te verminderen.
---
Liveness probes
Een liveness probe werkt zoals een readiness probe, maar in plaats van de container NotReady te maken, doodt de liveness probe de container. Kubernetes start de container vervolgens opnieuw op basis van het restartPolicy (standaard "Always").
apiVersion: "v1"
kind: "Pod"
metadata:
name: "pod-a"
spec:
containers:
- name: "app"
image: "my-app:latest"
startupProbe:
httpGet:
path: "/startup"
port: 8080
periodSeconds: 1
failureThreshold: 5
livenessProbe:
httpGet:
path: "/live"
port: 8080
periodSeconds: 2
failureThreshold: 1
Dit is nuttig wanneer een container niet zelf kan herstellen, bijvoorbeeld bij een deadlock in de main thread.
Opmerking over een Kubernetes bug: Er is een bekende bug (geïntroduceerd in v1.35.0) waarbij liveness probes soms worden afgevuurd voordat de startup probe succesvol is afgerond, wat kan leiden tot onnodige restarts.
Verkeerde configuratie van liveness probes
Een veelgemaakte fout is het controleren van externe afhankelijkheden (zoals een database) in een liveness probe. Als de database tijdelijk uitvalt, zullen álle containers hun liveness probe falen en tegelijkertijd herstarten.
Dit kan leiden tot een thundering herd-effect: zodra de database weer up is, worden alle containers tegelijk herstart en worden ze onmiddellijk overspoeld met een enorme hoeveelheid opgespaard verkeer, waardoor ze opnieuw crashen (cascading failure).
Advies: Laat een liveness probe alleen falen wanneer het probleem lokaal is voor één container en een restart waarschijnlijk helpt.
---
Probes en Deployments
In Kubernetes zijn veel velden van een Pod-spec onveranderlijk (immutable). Een Deployment werkt updates uit via een "rollout" (RollingUpdate).
De belangrijkste parameters hierbij zijn:
maxUnavailable: Hoeveel pods er tijdens de rollout niet beschikbaar mogen zijn.maxSurge: Hoeveel extra pods er boven het gewenste aantal mogen worden aangemaakt.
Probes spelen een directe rol in de snelheid van deze rollout. Een nieuwe pod moet namelijk eerst zijn probes (startup en readiness) passeren voordat Kubernetes de oude pods begint te verwijderen. Als de periodSeconds van een probe hoog is, duurt de volledige rollout langer.
Zonder probes worden containers direct als 'Ready' beschouwd, wat de rollout versnelt, maar er wel voor zorgt dat requests falen omdat de applicatie nog niet echt is opgestart.
---
Tips voor het ontwerpen van probe-endpoints
Startup
- Gebruik ze bij trage of variabele opstarttijden.
- Controleer frequent om initialisatie snel te detecteren. Verhoog de
failureThresholdom de totale wachttijd te behouden. - Gebruik een apart
/startupendpoint voor specifieke initialisatiechecks (zoals het laden van caches).
Readiness
- Houd deze probe "goedkoop" (lage resource-impact) en conservatief.
- Laat de probe niet falen op basis van gedeelde afhankelijkheden (databases, API's), tenzij de container echt geen enkel nuttig verkeer kan verwerken zonder deze.
- Laat de probe niet falen bij een hoge CPU- of geheugenbelasting; het verwijderen van een replica kan dan juist leiden tot een cascading failure op de overgebleven pods.
Liveness
- Laat deze probe alleen falen als het zeer waarschijnlijk is dat de container vastzit en een restart helpt. Bij twijfel: geef succes terug.
- Laat de probe niet falen op basis van gedeelde afhankelijkheden.
- Laat de probe niet falen bij hoge CPU- of geheugenbelasting.
Algemeen advies
- Houd probes begrensd en goedkoop om clusterresources te sparen.
- De standaard
failureThresholdis 3. Verlaag dit alleen als onmiddellijke interventie belangrijker is dan het risico op reacties op tijdelijke storingen.
Groetjes,