An Ingress returns 503 while the Service's Pods appear up — trace where traffic is lost.
An Ingress returns 503 for an app, but the Pods are running. Trace the request path Ingress → Service → endpoints → Pod, find where it breaks, and give the fix.
$ curl -sI https://app.example.com/ | head -1
HTTP/2 503
$ kubectl get pods -l app=api
NAME READY STATUS RESTARTS AGE
api-abc 0/1 Running 0 2m
api-def 0/1 Running 0 2m
$ kubectl get endpoints api
NAME ENDPOINTS AGE
api <none> 30m
Diagnose and fix.
A 503 with kubectl get endpoints api empty means the Service has no ready backends, so kube-proxy cannot route. Two causes: the readiness probe never passes, so Pods stay 0/1 Running and out of the Service, or the Service selector misses the Pod labels.
- ✗Blaming the Ingress controller before checking the Service endpoints
- ✗Forgetting a not-Ready Pod is removed from the Service endpoints
- ✗Overlooking a Service selector that does not match the Pod labels
- →How does a readiness probe differ from a liveness probe in this failure?
- →What command compares a Service's selector against a running Pod's labels?
Solution
1. Walk the request path
Ingress → Service → Endpoints → Pod
$ kubectl get endpoints api # api <none> ← breaks here
endpoints is empty → the Service has no ready backends, so the Ingress returns 503 (no upstream). The break is between the Service and the Pods.
2. Two causes of empty endpoints
excluded from endpoints. Check describe pod → Readiness probe failed, fix the probe/app.
— endpoints is then empty even when Pods are 1/1 Ready.
- Readiness never passes: Pods are
0/1 Running(as here) — a not-Ready Pod is - Selector mismatch:
Service.spec.selectordoes not match the Pods'metadata.labels
3. Telling them apart, and the fix
$ kubectl get pod api-abc -o jsonpath='{.metadata.labels}' # Pod labels
$ kubectl get svc api -o jsonpath='{.spec.selector}' # selector
Match but endpoints empty → readiness. Do not match → fix the selector/labels.