A failing readiness probe prevents a pod from receiving traffic. The readiness probe indicates if a container is ready to serve requests. When it fails, the pod is removed from load balancing but the container keeps running, allowing debugging without service disruption.
The readiness probe signals: "Am I ready to handle traffic?" When it fails: - Pod is removed from service endpoints (no traffic sent) - Container continues running (no restart) - Load balancer stops routing requests to the pod Unlike liveness probes (which restart), readiness probes allow graceful degradation. A failing readiness probe is often temporary (warming up, waiting for dependencies) and resolves without intervention.
Check the current probe settings:
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 "Readiness"
kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A 10 "readinessProbe:"
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.conditions[?(@.type=="Ready")]}'Example output:
Readiness: http-get delay=10s timeout=5s period=10s #success=1 #failure=3Note: delay (initialDelaySeconds), timeout, period, and thresholds.
View what the application is doing:
kubectl logs <pod-name> -n <namespace> -f
kubectl logs <pod-name> -n <namespace> --tail=100 | grep -i "ready\|waiting\|error"
# Check for repeated failures:
kubectl logs <pod-name> -n <namespace> | head -30 # First log lines
kubectl logs <pod-name> -n <namespace> | tail -30 # Last log linesLook for:
- "Database not connected"
- "Cache not initialized"
- "Waiting for dependencies"
Run the readiness check from inside the pod:
# Execute the probe command directly:
kubectl exec -it <pod-name> -n <namespace> -- sh
# For HTTP probe:
curl -v http://localhost:8080/ready
curl -v http://localhost:8080/readiness
echo $? # Should return 0 and HTTP 200
# For TCP probe:
nc -zv localhost 8080
# For exec probe:
/bin/ready-check.sh
# Check response time:
time curl http://localhost:8080/readyIf the probe fails or times out, you've found the issue.
Verify the application can reach its dependencies:
# From inside the pod:
kubectl exec -it <pod-name> -n <namespace> -- sh
# Check database connectivity:
nc -zv database-host 5432
psql -h database-host -U user -d mydb -c "SELECT 1"
# Check cache/Redis:
redis-cli -h redis-host ping
# Check other services:
curl -v http://api-service:8080/health
# Check DNS:
nslookup database-host
getent hosts database-hostIf dependencies are unreachable, the readiness check will fail.
Give the application more time to initialize:
# Patch the deployment:
kubectl patch deployment <name> -n <namespace> -p '{"spec":{"template":{"spec":{"containers":[{"name":"<container>","readinessProbe":{"initialDelaySeconds":60}}]}}}}'
# Or edit YAML:
kubectl edit deployment <name> -n <namespace>Example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ready-app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 45 # Wait 45 seconds before first check
periodSeconds: 10
failureThreshold: 3Rule: initialDelaySeconds should be > max startup time.
Allow more time for the probe to complete:
kubectl patch deployment <name> -n <namespace> -p '{"spec":{"template":{"spec":{"containers":[{"name":"<container>","readinessProbe":{"timeoutSeconds":10}}]}}}}'
# Or edit YAML:readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 10 # Increase from default 1 to 10
failureThreshold: 3Timeout should be reasonable (3-10s) but not excessive.
Create a readiness check that verifies initialization:
# Python/Flask example:
@app.route('/ready', methods=['GET'])
def readiness():
"""Readiness check: is the app ready to serve traffic?"""
try:
# Check if application has completed initialization
if not app.config.get('initialized'):
return jsonify({'status': 'not_ready'}), 503
# Check database connectivity
db.session.execute('SELECT 1')
# Check cache (optional)
if app.config.get('use_cache'):
cache.ping()
return jsonify({'status': 'ready'}), 200
except Exception as e:
print(f"Readiness check failed: {e}")
return jsonify({'status': 'error', 'message': str(e)}), 503Return 200 only when truly ready. Use 503 for not ready (load balancer will remove from endpoints).
Readiness probes should check only if the pod is ready, not if external services are available:
Bad (checks external service):
readinessProbe:
httpGet:
path: /api/external-service/status
port: 8080If external service is down, your pod becomes NotReady, cascading failure.
Good (checks local readiness):
readinessProbe:
httpGet:
path: /ready # Just check if app is initialized
port: 8080If external service is needed, handle it gracefully in the application (retry, cache, fallback).
Unlike liveness probes, readiness failures don't restart containers—they just remove the pod from load balancing. This is useful for: slow startups, temporary unavailability of dependencies, or rolling updates. Use liveness for "is the container alive" and readiness for "is it ready to serve". A pod can be Running but not Ready. Always implement proper health check endpoints rather than relying on default probes. In cloud environments (AKS, EKS), ensure network policies allow readiness checks from the kubelet. Startup probes (K8s 1.18+) are better than high initialDelaySeconds for slow-starting apps. For databases, use readiness checks to detect unavailability but continue running—don't cascade failures. Implement exponential backoff in application startup to avoid probe failures during load.
No subnets found for EKS cluster
How to fix "eks subnet not found" in Kubernetes
unable to compute replica count
How to fix "unable to compute replica count" in Kubernetes HPA
error: context not found
How to fix "error: context not found" in Kubernetes
default backend - 404
How to fix "default backend - 404" in Kubernetes Ingress
serviceaccount cannot list resource
How to fix "serviceaccount cannot list resource" in Kubernetes