# Kubernetes pod Running but 0/1 Ready: readiness probe failing

The container is up but its readiness probe fails, so the pod is cut out of every Service that selects it — and, unlike a liveness failure, nothing is restarted. The probe's own error text in the pod Events says whether the probe is wrong or the app genuinely is not ready.

> Confidence: high · Verified: 2026-08-11 · Status: fresh · Source: https://knowbase.sh/k/kubernetes-pod-running-not-ready

## Error signature

```
Readiness probe failed
```

Codes: Unhealthy, Ready=False, ContainersReady=False

## Problem

kubectl get pods shows Running with READY 0/1 and zero restarts, and it stays that way. Requests through the Service skip the pod entirely, a rolling update hangs at "1 old replicas are pending termination", and nothing crashes — so there is no restart loop to read and kubectl logs often looks perfectly healthy. The failure lives in the readiness probe's verdict, which only surfaces in the pod's Events and conditions, not in the application log.

## Root cause

- **The probe checks the wrong port, path, or scheme** _(primary)_
  - The readinessProbe was copied from another service or drifted from the app: it points at a port the container never listens on, a path the server answers with 404, or plain HTTP against a TLS-only port. The app is fine; the probe can never succeed.
  - How to tell: Events repeat the same error forever — 'HTTP probe failed with statuscode: 404' or 'connection refused' — and requesting the probe's exact port and path by hand inside the pod fails identically while the app's real endpoint works
- **The app starts slower than the probe allows** _(common)_
  - initialDelaySeconds plus periodSeconds times failureThreshold is shorter than the app's real warm-up — JVM start, cache load, migrations. The pod eventually becomes Ready on quiet nodes and stays unready on slow ones, which reads as flakiness.
  - How to tell: The same manifest sometimes reaches 1/1 after a delay, and running the probe's check by hand succeeds once the app has been up long enough
- **The readiness check tests a shared dependency** _(common)_
  - The health endpoint pings the database or a downstream API. When that dependency degrades, every replica fails readiness at once, all pod IPs leave the EndpointSlices together, and a partial outage becomes a total one.
  - How to tell: All replicas flip to 0/1 at the same moment, and the timing matches an incident on the dependency the health endpoint checks
- **The app listens on localhost instead of the pod IP** _(common)_
  - The kubelet connects to the pod's IP address, not to 127.0.0.1. A server bound to loopback answers a curl from inside the container but refuses the probe's connection from outside it.
  - How to tell: Inside the container, curl to 127.0.0.1:<port> succeeds while curl to the pod IP on the same port is refused; ss -ltn shows the listener bound to 127.0.0.1
- **A readinessGate condition was never set to True** _(edge)_
  - The pod spec declares readinessGates — commonly injected by load-balancer controllers — and the controller that should PATCH the condition into status.conditions is missing, broken, or lacks RBAC. Every container is ready but the pod as a whole never is, and no probe event explains it.
  - How to tell: kubectl describe shows Ready False with ContainersReady True, and the Readiness Gates section lists a condition that is False or absent

## Solution

1. Read the Unhealthy events on the pod. The kubelet quotes the probe's own failure — status code, connection refused, timeout — and that string separates a wrong probe from a slow or broken app.

```bash
kubectl describe pod <pod-name> -n <namespace>
```

   Note: No Unhealthy events at all while READY stays 0/1 points away from probes — check the conditions in the next step for a readiness gate.
2. Compare the pod's conditions. ContainersReady False means a container's readiness probe is failing; ContainersReady True with Ready False means a readinessGate is the blocker and no probe change will help.

```bash
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{range .status.conditions[*]}{.type}={.status}{"\n"}{end}'
```

3. Run the probe's exact check by hand, both against loopback and against the pod IP. Success on 127.0.0.1 with refusal on the pod IP means the server is bound to loopback; a 404 on both means the path is wrong; success on both means the timing, not the check, is at fault.

```bash
POD_IP=$(kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.podIP}')
kubectl exec <pod-name> -n <namespace> -- \
  sh -c "wget -qO- http://127.0.0.1:<port><path> && echo OK-loopback"
kubectl run probe-check --rm -it --image=curlimages/curl --restart=Never -n <namespace> -- \
  curl -sS -o /dev/null -w '%{http_code}\n' "http://$POD_IP:<port><path>"
```

4. Fix the probe to describe the app it actually fronts — the real containerPort, a path the server serves, and a budget that covers the slowest observed startup. Prefer failureThreshold headroom over a long initialDelaySeconds, which delays every pod including fast ones.

```yaml
readinessProbe:
  httpGet:
    path: /healthz        # must return 2xx-3xx from the app itself
    port: 8080            # a port the container really listens on, on the pod IP
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 6     # tolerates ~30s of warm-up after the delay
```

   Note: For genuinely slow starters, move the wait into a startupProbe so readiness keeps a tight period for the steady state.
5. Take shared dependencies out of the readiness check unless you want the whole fleet unrouted when that dependency blips. Readiness failure removes the pod from every matching Service's EndpointSlices, so a health endpoint that pings the database converts a database incident into zero endpoints anywhere.
6. If the blocker is a readinessGate, fix the controller that owns the condition rather than the pod — it must PATCH the condition into the pod's status. Confirm what the gate is waiting for, then check that controller's logs and RBAC.

```bash
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.readinessGates}{"\n"}{.status.conditions}'
```

7. Unblock the rollout. A deployment does not proceed past unready pods; it stalls until progressDeadlineSeconds (default 600) and then only reports ProgressDeadlineExceeded — Kubernetes never rolls back on its own. After fixing the probe or the app, restart the rollout and watch it complete.

```bash
kubectl rollout restart deployment/<name> -n <namespace> && kubectl rollout status deployment/<name> -n <namespace>
```


**Verify:** kubectl get pods shows 1/1 Ready with RESTARTS unchanged, kubectl get endpointslices -l kubernetes.io/service-name=<service> lists the pod IP with ready true, and kubectl rollout status reports the deployment successfully rolled out.

**If that fails:** If the app cannot expose a meaningful readiness endpoint, probe the cheapest truthful signal instead — a tcpSocket check on the serving port — rather than deleting the probe: with no readinessProbe the pod counts Ready the moment the container starts, and a rolling update will happily shift traffic onto replicas that cannot serve yet.

## Applies to

- Kubernetes: 1.14 and later — Pod readiness gates are stable since 1.14; current docs describe endpoint removal via the EndpointSlice controller.
- kubelet: 1.14 and later — Runs readiness probes for the container's whole lifecycle; a failed result marks the pod unready but never restarts anything.
- Platforms: linux/amd64, linux/arm64

## Not applicable to

- Liveness probe failures, which restart the container and show a climbing RESTARTS count — that is kubernetes-crashloopbackoff territory, not this
- A Service with zero endpoints because its selector matches no pods (kubernetes-service-no-endpoints) — there the pods can be 1/1 Ready and traffic still goes nowhere
- Startup probe failures, which kill the container and hand it to the restart policy rather than leaving it Running and unready
- Pods stuck in Pending, which were never scheduled and have no probes running at all
- Endpoints marked not-ready during pod termination, which is the normal drain path and not a probe failure

## Evidence

1. [Liveness, Readiness, and Startup Probes](https://kubernetes.io/docs/concepts/configuration/liveness-readiness-startup-probes/) — The Kubernetes Authors (official-docs), read 2026-08-11
   Supports: That a failed readiness probe removes the pod's IP from the EndpointSlices of every Service selecting it — traffic removal, not a restart — which is the core semantic this entry rests on and the reason a dependency-checking readiness endpoint can unroute a whole fleet.
   > If the readiness probe returns a failed state, the EndpointSlice controller removes the Pod's IP address from the EndpointSlices of all Services that match the Pod.
2. [Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — The Kubernetes Authors (official-docs), read 2026-08-11
   Supports: The liveness/readiness contrast in one place: a failed liveness probe restarts the container, a failed readiness probe only marks the pod unready and stops Service traffic to it.
   > If the liveness probe fails, the container will be restarted. ... If the readiness probe fails, the pod will be marked unready and will not receive traffic from any services.
3. [Pod Lifecycle — Pod readiness](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/) — The Kubernetes Authors (official-docs), read 2026-08-11
   Supports: That readinessGates add extra conditions the kubelet folds into pod readiness, so a pod whose containers are all ready can still be Ready False — the root cause with no probe events.
   > set readinessGates in the Pod's spec to specify a list of additional conditions that the kubelet evaluates for Pod readiness.
4. [Deployments — Failed Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) — The Kubernetes Authors (official-docs), read 2026-08-11
   Supports: That a rollout whose new pods never become ready stalls rather than fails fast, and that progressDeadlineSeconds only controls when the stall is reported in status.
   > .spec.progressDeadlineSeconds denotes the number of seconds the Deployment controller waits before indicating (in the Deployment status) that the Deployment progress has stalled.

## Confidence

high — The endpoint-removal semantics, the restart-vs-unrouted contrast, the readinessGates mechanism and the rollout-stall behaviour are all quoted from current Kubernetes documentation. The individual misconfiguration causes — wrong port or path, loopback binding, dependency-checking health endpoints — and their discriminators are operational practice built on those documented mechanics rather than claims any single page makes, as is the advice to prefer failureThreshold headroom over a long initialDelaySeconds.

## If this is not your failure

Look yours up instead of adapting this one: https://knowbase.sh/search.json?q=<your error text>

To narrow the causes above to the one you have, run the discriminator on each and POST
`{"slug":"kubernetes-pod-running-not-ready","observations":"<what they returned>"}` to https://knowbase.sh/diagnose.json.
It answers with the cause your observations identify and why the others are excluded.

When diagnosis returns an identifiedResolution, run that recipe and its verification criteria,
then POST the completion body it supplies to https://knowbase.sh/outcome.json.
Only a completion response with status=resolved may be presented as resolved; its receipt is agent-observed, not independently verified.

The same workflow is available as MCP tools: https://knowbase.sh/mcp

---

Retrieved from https://knowbase.sh/k/kubernetes-pod-running-not-ready · knowbase · CC-BY-4.0
