Probes: Liveness, Readiness, and Startup
The idea in one sentence
Section titled “The idea in one sentence”Three different probes ask three different questions — is it alive, is it ready for traffic, and has it finished starting up — and Kubernetes reacts differently to each answer.
Liveness vs readiness: restart vs remove-from-Service
Section titled “Liveness vs readiness: restart vs remove-from-Service”A liveness probe answers “is this container still working?” If it fails enough times in a row, the kubelet kills the container and lets restartPolicy decide what happens next (normally, it gets restarted). This is for containers that are still running but stuck — deadlocked, wedged, unable to make progress — where a restart is the fix.
A readiness probe answers a completely different question: “is this container ready to serve traffic right now?” A failing readiness probe does not restart anything. Instead, the Pod is removed from the Service’s Endpoints/EndpointSlice, so the Service simply stops routing traffic to it. The container keeps running untouched, and as soon as the probe starts succeeding again, the Pod is added back.
This distinction is what makes rolling updates and slow-warm-up applications work correctly:
apiVersion: v1kind: Podmetadata: name: web labels: app: webspec: containers: - name: web image: web-app:1.4.0 ports: - containerPort: 8080 livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 readinessProbe: httpGet: path: /ready port: 8080 periodSeconds: 5 failureThreshold: 1A common real-world misconfiguration is skipping the readiness probe entirely. With no readiness probe, Kubernetes considers a container ready the instant it starts — even if the application inside is still loading a config file, warming a cache, or opening database connections. During a rollout, that means live traffic gets routed straight into a container that cannot actually handle it yet, which shows up as a burst of errors right after every deployment.
Startup probe: giving slow-starting containers room to boot
Section titled “Startup probe: giving slow-starting containers room to boot”Some containers — legacy JVM apps, anything doing a heavy migration or cache preload on boot — can take minutes to become responsive. A short initialDelaySeconds on the liveness probe is not enough headroom, but a long one delays detecting a real hang once the app is finally up.
A startup probe solves this. While the startup probe has not yet succeeded, the liveness and readiness probes are disabled entirely — so a slow-booting container cannot be killed by an impatient liveness probe. Once the startup probe succeeds once, it stops running permanently, and liveness/readiness take over for the rest of the container’s life.
startupProbe: httpGet: path: /healthz port: 8080 failureThreshold: 30 periodSeconds: 10With failureThreshold: 30 and periodSeconds: 10, this container gets up to 300 seconds to become healthy before the kubelet gives up and restarts it.
# Watch probe-driven restarts and readiness statekubectl get pods -wkubectl describe pod web | grep -A5 -E 'Liveness|Readiness|Startup'Probe mechanisms
Section titled “Probe mechanisms”Every probe type (liveness, readiness, startup) can use one of these check mechanisms:
httpGet— send an HTTP GET request; any status code from 200 up to but not including 400 counts as success.tcpSocket— try to open a TCP connection to a port; a successful connection counts as success.exec— run a command inside the container; exit code0counts as success.grpc— call the container’s gRPC health-checking service (the container must implement the standard gRPC health protocol).
readinessProbe: grpc: port: 5000Tuning fields apply across mechanisms: initialDelaySeconds (wait before the first check), periodSeconds (how often to check), timeoutSeconds (how long to wait for a response), failureThreshold (consecutive failures before acting), and successThreshold (consecutive successes needed to flip back to healthy — must be 1 for liveness and startup probes).
flowchart LR
boot["Container starts"] --> sp{"startupProbe\nsucceeded?"}
sp -- "no, keep trying" --> sp
sp -- "yes" --> live["livenessProbe\nruns continuously"]
sp -- "yes" --> ready["readinessProbe\nruns continuously"]
live -- "fails" --> restart["kubelet restarts container"]
ready -- "fails" --> remove["Pod removed from Service Endpoints"]
ready -- "succeeds again" --> add["Pod added back to Endpoints"]