Ein grünes Pod-Icon ist nicht dasselbe wie bereit für Passagiere. Readiness-Probes sind die Unterscheidung. Diese Lektion habe ich mehr als einmal gelernt: durch Datenverkehr auf Instanzen, die zwar liefen, aber noch nicht bedienen konnten, und durch Readiness-Probes, die logen, weil wir sie auf den falschen Endpoint zeigten.

Foto von Pixabay auf Pexels
Dieser Beitrag handelt davon, was Bereitschaft in der Praxis bedeuten sollte, wie sie sich von Lebendigkeit unterscheidet, welche Fehler ich noch sehe (und selbst gemacht habe) und wie man Probes so einstellt, dass sie die Realität abbilden statt Tutorial-Defaults. Ich bin kein Kubernetes-Internals-Experte. Ich bin jemand, der gepaged wurde, weil / 200 zurückgab, während die Anwendung dahinter nicht arbeitsfähig war.
Was Bereitschaft bedeuten soll
Eine Frage beantworten: Soll dieser Pod gerade Datenverkehr erhalten?
Das ist etwas anderes als „läuft der Prozess” oder „ist der Container gestartet”. Ein Java-Service kann laufen, während GC-Pausen ihn zu einem schlechten Ziel machen. Ein Webserver kann auf Port 8080 lauschen, während Migrationen noch laufen. Ein Worker kann lebendig sein, aber absichtlich keine Queue abarbeiten, weil er auf Cache-Warmup wartet.
Readiness steuert Service-Endpoints und Load-Balancer-Backends. Wenn die Readiness-Prüfung fehlschlägt, wird der Pod bei einem Standard-Service aus den Endpoints entfernt. Datenverkehr sollte diese Instanz erst wieder erreichen, wenn die Readiness-Probe besteht. Das ist kontrollierte Degradierung auf Pod-Ebene, wenn die Probes ehrlich sind.
Typische Readiness-Prüfungen:
- Anwendung hat den Start abgeschlossen und kann Anfragen innerhalb des SLO bedienen
- Datenbankmigrationen abgeschlossen (wenn sie beim Start laufen)
- Kritische Abhängigkeiten erreichbar — Cache, DB, Identity Provider — innerhalb akzeptabler Grenzen
- Feature Flags und Config geladen
- Bei Workern: bereit, Arbeit zu übernehmen, nicht nur lebendig
Was Readiness nicht zu garantieren vorgeben sollte:
- Volle Abhängigkeitsgesundheit für den gesamten Stack
- Korrektheit der Geschäftslogik
- Null Latenz für immer
Readiness ist ein Tor für Datenverkehr, kein moralisches Urteil über die Architektur.
Liveness ist eine andere Frage
Liveness fragt: Soll Kubernetes diesen Container neu starten?
Readiness und Liveness zu vermischen erzeugt zwei schmerzhafte Muster:
- Restart-Loops — Liveness-Probe schlägt bei langsamem Start fehl; kubelet beendet den Container wiederholt; man erreicht nie Ready.
- Datenverkehr zu halbtoten Instanzen — Readiness besteht bei einer oberflächlichen Prüfung, während die Anwendung keine sinnvolle Arbeit leisten kann; Liveness greift nie, weil der Prozess auf HTTP antwortet.
Die Luftfahrt-Analogie, dezent gehalten: Vor dem Start prüft man Punkte, die für diesen Flug zählen. Readiness ist diese Prüfung für den Service. Liveness ist eher „läuft der Motor noch” — ein gröberes Signal, dass etwas Grundlegendes fehlgeschlagen ist und ein Neustart nötig ist, nicht nur das Herausnehmen aus der Rotation.
Daumenregel, die ich nutze:
- Readiness schlägt fehl → Datenverkehr stoppen, vielleicht ohne Neustart erholen
- Liveness schlägt fehl → kubelet startet den Container neu
Wenn eine langsame Abhängigkeit die Instanz aus dem Datenverkehr nehmen, aber den Prozess nicht beenden soll, gehört das in die Readiness-Probe, nicht in Liveness.
Wie Kubernetes Probe-Ergebnisse nutzt
Der kubelet führt Probes nach dem Zeitplan im Pod Spec aus. Ein Readiness-Fehlschlag entfernt die Pod-IP aus Endpoints-Objekten, die den Pod selektieren. Bestehende Verbindungen können je nach Konfiguration bestehen bleiben; neue sollten nicht ankommen. Wenn Readiness wieder besteht, kehrt der Pod in die Rotation zurück.
Bei Rolling Updates steuert Readiness, wann das neue ReplicaSet als verfügbar gilt. Eine zu strenge Readiness-Probe kann einen Deploy blockieren. Eine zu lockere markiert den Rollout als erfolgreich, während Instanzen noch warm werden. Dann steigen Fehlerraten, sobald Datenverkehr umgeschaltet wird.
Bei OpenShift folgen Routes und Services derselben Endpoint-Semantik für bereite Adressen. Operatoren, die Deployments verwalten, respektieren trotzdem die Probe-Konfiguration im Pod Template. Plattformteams injizieren manchmal Defaults; Anwendungsteams sollten sie prüfen, statt sie anzunehmen.
Diesen Ablauf zu verstehen hilft beim Debuggen: kubectl get pods mit Running heißt nicht Ready. Die Ready-Spalte prüfen. Endpoints prüfen:
kubectl get pods -l app=checkout -o wide
kubectl get endpoints checkout -o yaml
kubectl describe pod <pod-name> | grep -A10 Readiness
Ist Ready false, sollte kein Datenverkehr den Pod treffen. Ist Ready true und Nutzer sehen trotzdem Fehler, misst die Probe nicht das, was man glaubt.
HTTP, TCP, exec — den Probe-Typ wählen
HTTP GET ist die Standardwahl für Web-Services. Er sollte auf einen dedizierten Readiness-Pfad zeigen, nicht unbedingt auf /.
TCP socket prüft, dass ein Port Verbindungen annimmt. Schnell und einfach. Gefährlich wird das, wenn der Prozess lauscht, bevor die Anwendungslogik bereit ist — bei vielen Frameworks üblich.
Exec führt einen Befehl im Container aus. Flexibel, aber schwergewichtiger und in Produktion schwieriger zu durchdenken. Nützlich, wenn Readiness ein lokales Skript braucht, das mehrere interne Bedingungen prüft.
Beispiel für eine erste HTTP-Readiness-Probe, bevor ich sie anpasse:
readinessProbe:
httpGet:
path: /ready
port: 8080
scheme: HTTP
periodSeconds: 10
timeoutSeconds: 2
successThreshold: 1
failureThreshold: 3
initialDelaySeconds: 5
Und eine Liveness-Probe, die absichtlich einfacher und toleranter bleibt:
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 3
initialDelaySeconds: 30
Beachte /ready versus /healthz. Verschiedene Pfade, verschiedene Semantik, implementiert im Anwendungscode. Das Anwendungsteam muss diese Handler verantworten. Plattform-YAML allein kann sie nicht erfinden.
/ready ehrlich implementieren
Ein Readiness-Handler sollte die Prüfungen ausführen, wegen derer man Datenverkehr bewusst stoppen würde, nicht jede Prüfung, die man sich wünscht.
Gute Muster:
GET /ready
200 if: migrations done, DB ping < 500ms, cache client connected
503 if: any required dependency unavailable
Schlechte Muster:
GET /ready
200 always if main() started
Ebenfalls schlecht:
GET /ready
runs full checkout integration test including third-party sandbox
Das zweite schlechte Muster markiert Pods als nicht bereit, wenn die Sandbox kurz aussetzt, und nimmt während des Ausfalls eines Dritten Kapazität offline. Das dritte markiert Pods als bereit, wenn nur der Prozess existiert. kube schickt Datenverkehr, Nutzer bekommen 500er.
Ich bevorzuge explizite JSON-Bodies fürs Debugging:
{"ready": false, "reason": "database_migrations_pending"}
Logs und describe-Ausgabe lassen sich leichter mit Metriken korrelieren.
Bei gRPC-Services sollte man grpc probes nutzen (in modernem Kubernetes unterstützt) oder bei Bedarf einen kleinen Sidecar-HTTP-Übersetzer. Nicht so tun, als wäre TCP auf dem gRPC-Port dasselbe wie Anwendungsbereitschaft.
Häufige Fehler, die ich noch sehe
HTTP-Probe auf /, obwohl die Zustandsprüfung eigentlich auf /ready liegt. Die Root-Seite liefert statische Inhalte oder Redirects, während die Backend-Initialisierung weiterläuft. Die Marketing-Site bleibt grün; die API ist es nicht.
initialDelaySeconds zu niedrig. Probe schlägt beim normalen Start fehl; Pod wechselt zwischen bereit und nicht bereit; Rolling Update schließt nie ab oder alte Pods tragen den gesamten Datenverkehr, bis neue zufällig bestehen.
Probe besteht, während Caches warm werden. Die Fehlerrate steigt nach dem Deploy, weil Readiness vor Ende des Warmups bestand. Abhilfe: Readiness wartet auf Warmup oder ein progressiver Canary mit Metrik-Gates außerhalb von kube.
Gar keine Probe. kube denkt, alles ist in Ordnung, weil der Container läuft. Das ist die Voreinstellung in zu vielen internen Templates.
Readiness prüft die gesamte Abhängigkeitskette. Eine langsame Abhängigkeit entfernt alle Pods aus dem Service: Totalausfall statt kontrolliertem Teilausfall. Manchmal ist das Absicht, oft nicht.
Gleiche Timeouts für Liveness und Readiness. Liveness sollte langsamer und weniger empfindlich sein, um Restart-Stürme zu vermeiden.
Startup Probes ignorieren. Kubernetes Startup Probes schützen, wenn sie genutzt werden, langsam startende Container beim Boot, damit Liveness sie nicht vorzeitig beendet. Readiness steuert den Datenverkehr trotzdem erst nach dem Start.
Ich habe mehr als einen dieser Fehler ausgeliefert. Das Muster nach dem Incident ist immer ähnlich: Wir hielten Running für bereit; wir hielten / für bereit; wir hielten Defaults aus einem vier Jahre alten Blogpost für passend zu unserem JVM-Heap-Verhalten.
Tuning aus Messung, nicht aus Tutorials
Probe-Werte aus einem Tutorial zu kopieren ist der Weg zu periodSeconds: 10 überall. Besser ist Tuning anhand von Startkurven und Verhalten der Abhängigkeiten.
Prozess:
- In Staging deployen, wobei Readiness fehlschlägt, bis die Anwendung ein internes „ready”-Flag ehrlich setzt.
- Zeit vom Container-Start bis zur echten Bereitschaft für Produktionsdatenverkehr messen — p95, nicht Best Case.
initialDelaySecondsmit Reserve unterhalb dieses p95 setzen oder eine Startup Probe für lange Starts verwenden.timeoutSecondsoberhalb der schlechtesten Handler-Zeit unter Last setzen.failureThresholdso setzen, dass kurze Ausschläge Pods nicht sofort entfernen, aber nicht so hoch, dass schlechte Instanzen minutenlang in Rotation bleiben.
Während des Rollouts beobachten:
kubectl rollout status deployment/checkout -n production
kubectl get pods -l app=checkout -w
Mit Anwendungsmetriken korrelieren: Fehlerrate, Latenz, Pool-Verbindungen. Wenn Ready im selben Moment true wird, in dem Fehler steigen, hat die Probe gelogen.
Bei OpenShift-Deployments verhält sich oc rollout status ähnlich. Route-Backends prüfen, wenn externes Monitoring trotz Ready Fehler zeigt. Caching-Layer und CDN-Origins liegen außerhalb von kube Probes.
Readiness beim Shutdown
Readiness sollte fehlschlagen, wenn der Pod geordnet terminiert, damit Load Balancer neue Anfragen stoppen, bevor das SIGTERM-Handling abgeschlossen ist. PreStop Hooks und Readiness implementieren zusammen graceful drain:
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
readinessProbe:
httpGet:
path: /ready
port: 8080
Anwendungscode sollte Readiness bei SIGTERM nach der Deregistrierung ebenfalls fehlschlagen lassen. Das genaue Muster hängt vom Framework ab. Ziel: neue Arbeit stoppen, laufende Arbeit innerhalb von terminationGracePeriodSeconds beenden, dann beenden.
Wer das überspringt, produziert 502er bei Node Drains und Deploys, selbst wenn Probes im Normalzustand perfekt aussahen.
Wann keine Readiness-Probe sinnvoll ist
Nicht jeder Pod braucht eine Readiness-Probe. Batch Jobs, einmalige CronJobs und reine Worker ohne Services brauchen vielleicht Liveness oder gar nichts, aber keine HTTP-Readiness auf einem bedeutungslosen Port.
Stateful Systeme mit langer Leader Election brauchen vielleicht eine eigene Readiness-Prüfung, die nur für den gewählten Leader bereit zurückgibt, nicht für Follower. Datenverkehr an alle Replikas zu schicken, wenn nur eine Replik Schreibzugriffe bedienen soll, ist ein Designproblem, das Probes abbilden müssen.
DaemonSets, die node-lokale Services bereitstellen, brauchen trotzdem ehrliche Readiness, wenn etwas davor über Nodes verteilt.
Automatisierung und GitOps
Probes gehören in die Versionskontrolle neben das Deployment-Manifest. Man sollte sie in Pull Requests wie Anwendungscode prüfen. Ein verschärftes Timeout, Freitag nachmittag gemerged, kann zum Wochenendausfall werden.
Bei Helm Charts sollte man Probe-Pfade und Schwellen als Values freigeben, aber sinnvolle Defaults und deren Begründung dokumentieren. Bei Kustomize Overlays sollte umgebungsspezifisches Tuning (Staging kürzer, Produktion strenger) in Diffs sichtbar sein.
Policy Engines (OPA Gatekeeper, Kyverno) können Readiness-Probes auf Deployments verlangen, wo Plattformstandards zählen. Ich bevorzuge zuerst Aufklärung und erst dann Policy, wenn Teams Probes wiederholt überspringen. Aber ich verstehe Plattformteams, die nach dem dritten vermeidbaren Incident Policy wählen.
Die Luftfahrt-Analogie, ehrlich gehalten
Vorflugkontrollen werden nicht gemacht, weil das Flugzeug meistens kaputt ist. Sie werden gemacht, weil manche Fehler am Boden leichter zu finden sind als nach dem Start. Readiness-Probes sind Bodenprüfungen für Instanzen. Sie garantieren keine Flugsicherheit — Architektur, Limits und Operatoren zählen trotzdem — aber sie verhindern, dass offensichtlich unbereite Pods Datenverkehr erhalten.
Man sollte die Metapher nicht zu weit treiben. Piloten starten Motoren nicht alle zehn Sekunden wegen automatischem Nörgeln neu. Kubernetes startet bei Liveness-Failure neu. Probes sollten so gestaltet sein, dass sie angemessen nörgeln.
Was ich noch lerne
Anwendungsspezifische Eigenheiten dominieren. JVM-Services, Node Event Loops, Python WSGI Workers, .NET Generic Hosts — jedes hat Startverhalten, das ich aus YAML allein nicht vollständig vorhersagen kann. Ich rede mit Anwendungsentwicklern, statt zu raten.
Service Meshes fügen eine weitere Readiness-Geschichte hinzu: Sidecar bereit versus Anwendung bereit. Wenn Envoy läuft, die Anwendung aber nicht, kann Datenverkehr je nach Konfiguration trotzdem durch den Sidecar zu einem toten Backend fließen. Mesh-Dokumentation verdient eine eigene Seite; die Lektion hier ist: messen, was der Nutzer erlebt, nicht nur, was die Plattform sieht.
Ich lerne auch, wann Gates ganz aus kube herausgehören: Canaries auf Basis von Prometheus-Fehlerraten, Autoscaling auf Queue-Tiefe, Readiness nur als grobes Gate. Probes sind günstige Versicherung, wenn sie ehrlich sind. Sie sind nicht das ganze Zuverlässigkeitsprogramm.
Praktische Checkliste vor dem Merge
- Dedizierter Readiness-Endpoint im Anwendungscode implementiert
- Liveness-Endpoint einfacher und weniger anfällig für False Positives
- Pfade und Ports passen zur Container-Konfiguration
- Timeouts unter Last getestet, nicht im Leerlauf
- Rolling Update in Staging mit Metriken beobachtet
- Graceful Shutdown lässt Readiness vor dem Beenden fehlschlagen
- Runbook erwähnt, wie fehlgeschlagene Readiness von außen aussieht
Abschlussgedanke
Readiness-Probes sind langweilige Konfiguration, bis sie es nicht mehr sind. Wenn sie funktionieren, fühlen sich Deploys auf gute Weise langweilig an: Datenverkehr schaltet um, Fehlerraten bleiben flach, niemand wird wegen Warmup-500ern gepaged. Wenn sie versagen oder lügen, debuggt man mysteriöse Teilausfälle, die wie Load-Balancer-Geister wirken.
Grüne Pod-Icons sind verführerisch. Ich versuche, Ready=true als Behauptung zu behandeln, die Belege braucht, so wie ein Punkt in der Vorflugkontrolle erst erledigt ist, wenn man ihn wirklich geprüft hat, nicht wenn man annimmt, jemand anderes habe das getan. Manchmal liege ich trotzdem daneben. Startverhalten ehrlich messen und Probes nach Incidents korrigieren: So verbessere ich mich, ohne so zu tun, als kenne ich schon jede Boot-Geschichte jeder Anwendung.