Readiness Liveness Startup Probes
Configure Kubernetes health probes correctly. When to use each probe type, common mistakes, and production-ready probe configurations.
π‘ Quick Answer: Configure Kubernetes health probes correctly. When to use each probe type, common mistakes, and production-ready probe configurations.
The Problem
Kubernetes has three probe types that look similar but do very different things when they fail β mixing them up causes either restart loops (liveness checking something it shouldnβt) or pods stuck out of rotation forever (readiness never passing).
The Solution
The Three Probe Types
Liveness β Is the container running correctly? Fails β container is restarted
Readiness β Is the container ready for traffic? Fails β removed from Service endpoints
Startup β Has the container finished starting? Fails after threshold β container is killed
Success β liveness/readiness begin checkingHTTP, TCP, Exec, and gRPC Probes
livenessProbe:
httpGet: {path: /health/live, port: 8080}
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet: {path: /health/ready, port: 8080}
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3# TCP β for services with no HTTP endpoint (databases, etc.)
livenessProbe:
tcpSocket: {port: 5432}
initialDelaySeconds: 30
periodSeconds: 10# Exec β for anything checkable via a local command
readinessProbe:
exec: {command: ["pg_isready", "-U", "postgres"]}
livenessProbe:
exec: {command: ["redis-cli", "ping"]}# gRPC (Kubernetes 1.24+) β no sidecar/wrapper needed
livenessProbe:
grpc: {port: 50051}
readinessProbe:
grpc: {port: 50051, service: "health"} # optional: specific gRPC health serviceStartup Probe for Slow-Starting Apps
Liveness and readiness donβt run until the startup probe succeeds β this prevents a slow-booting app from being killed by an impatient liveness probe before itβs even finished initializing:
startupProbe:
httpGet: {path: /health, port: 8080}
periodSeconds: 10
failureThreshold: 30 # 30 Γ 10s = up to 300s to start
livenessProbe:
httpGet: {path: /health, port: 8080}
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet: {path: /ready, port: 8080}
periodSeconds: 5Implementing Health Endpoints
# Flask
@app.route('/health/live')
def liveness():
return (jsonify(status='ok'), 200) if healthy else (jsonify(status='unhealthy'), 500)
@app.route('/health/ready')
def readiness():
return (jsonify(status='ready'), 200) if ready else (jsonify(status='not ready'), 503)func readinessHandler(w http.ResponseWriter, r *http.Request) {
if atomic.LoadInt32(&ready) == 1 {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable) // 503 removes the pod from Service endpoints
}
}Debugging Probe Failures
kubectl describe pod <pod> | grep -A 10 "Liveness\|Readiness"
kubectl get events --field-selector involvedObject.name=<pod>
# "Liveness probe failed: HTTP probe failed with statuscode: 500"
# "Readiness probe failed: connection refused"
# Test the endpoint manually to rule out a probe-config issue vs. an app issue
kubectl exec <pod> -- curl -s localhost:8080/health/liveCommon Issues
| Issue | Cause | Fix |
|---|---|---|
| Restart loop under load | Liveness probe checks a slow dependency (DB, downstream API) | Liveness should only check βis this process alive,β never external dependencies β put dependency checks in readiness instead |
| Pod never becomes Ready | Readiness endpoint checks something thatβs never true (e.g., a cache that only warms on first request) | Ensure the readiness condition is actually reachable during normal operation, not just at a specific lifecycle moment |
| Slow app killed before it finishes starting | No startup probe, and liveness failureThreshold Γ periodSeconds is shorter than actual startup time | Add a startupProbe with generous failureThreshold; liveness/readiness are paused until it succeeds |
timeoutSeconds errors under normal load | timeoutSeconds set higher than periodSeconds, so probes overlap | Keep timeoutSeconds comfortably below periodSeconds |
Best Practices
- Use separate endpoints for liveness and readiness (
/health/livevs/health/ready) β they check fundamentally different things - Keep liveness checks simple β verify the process itself is responsive, never call out to a database or downstream service
- Readiness should reflect real serving capacity β check dependencies here, and return non-2xx during shutdown/overload so traffic routes elsewhere
- Use a startup probe for anything slower than a few seconds to boot β itβs the correct tool, not a longer
initialDelaySecondson liveness - Donβt set
failureThreshold: 1β allow for at least one transient failure before taking action
Key Takeaways
- Liveness restarts the container; readiness removes it from Service endpoints; startup gates both until the app has actually finished booting
- HTTP probes treat 200-399 as success, 400+ as failure β return the right status code from your health endpoints, not just 200 always
- A startup probe prevents slow-starting apps from being killed by liveness before initialization completes
- Never put external dependency checks in a liveness probe β that turns a database blip into a full restart storm
kubectl describe podshows the exact probe failure message; test the endpoint manually withkubectl exec ... curlto isolate probe config from app bugs

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
