🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Kubernetes Ingress 503 Service Unavailable: 5 Causes and Fixes

Nginx Ingress returning 503 Service Unavailable? These 5 fixes cover no healthy backends, wrong service name, port mismatch, readiness probe failures, and connection refused — with exact kubectl commands.

Shubham4 min read
Share:Tweet

503 from Kubernetes Ingress means the Ingress controller cannot reach healthy backend pods. Here are the five causes, from most to least common.

Quick Diagnosis

bash
# Check if pods are running
kubectl get pods -n <namespace> -l app=<your-app>
 
# Check the Ingress
kubectl describe ingress <name> -n <namespace>
 
# Check nginx ingress controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=50 | grep 503
 
# Check if the service has endpoints
kubectl get endpoints <service-name> -n <namespace>
# If ENDPOINTS shows "none" — that is your problem

Cause 1: No Healthy Pod Endpoints

The most common cause. The Service exists but has no healthy pods behind it.

Check:

bash
kubectl get endpoints myapp-service -n production
# NAME             ENDPOINTS       AGE
# myapp-service    <none>          5m    ← Problem!

Why endpoints can be empty:

  • All pods are in Pending, CrashLoopBackOff, or Terminating
  • Pods exist but readiness probe is failing (pods are Running but not Ready)
  • Label selector in Service does not match pod labels

Fix — check pod labels vs service selector:

bash
# Service selector
kubectl get svc myapp-service -n production -o jsonpath='{.spec.selector}'
# {"app":"myapp","version":"v1"}
 
# Pod labels
kubectl get pod myapp-xyz -n production -o jsonpath='{.metadata.labels}'
# {"app":"myapp","version":"v2"}  ← Mismatch! version label differs

Fix the label mismatch in either the Service or the Deployment.

Cause 2: Wrong Service Name or Port in Ingress

yaml
# Broken Ingress
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - backend:
          service:
            name: myapp-svc        # Wrong — service is named 'myapp-service'
            port:
              number: 8080         # Wrong — service port is 80

Check:

bash
kubectl get svc -n production | grep myapp
# myapp-service   ClusterIP   10.0.0.1   <none>   80/TCP
 
kubectl describe ingress myapp-ingress -n production | grep -A 10 "Rules:"
# Shows what the Ingress is targeting

Fix:

yaml
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - backend:
          service:
            name: myapp-service    # Exact service name
            port:
              number: 80           # Service port, not container port

The port.number is the Service port (in spec.ports[].port), not the container port.

Cause 3: Readiness Probe Failing

Pods show as Running but are not Ready. Ingress only routes to Ready pods.

bash
kubectl get pods -n production
# NAME               READY   STATUS    RESTARTS
# myapp-xyz-abc      0/1     Running   0         ← 0/1 = not ready
 
# Check why
kubectl describe pod myapp-xyz-abc -n production | grep -A 15 "Readiness:"
# Shows readiness probe config and failure reason

Common readiness probe fixes:

yaml
readinessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 30     # Give app time to start
  periodSeconds: 10
  failureThreshold: 3
  timeoutSeconds: 5           # Increase if app is slow to respond

Test manually:

bash
kubectl exec -it myapp-xyz-abc -n production -- curl -s localhost:8080/health
# If this fails or hangs — that is your readiness probe failure

Cause 4: Ingress Class Missing or Wrong

In newer Kubernetes versions (1.18+), you must specify the ingress class.

bash
kubectl get ingressclass
# NAME    CONTROLLER             PARAMETERS   AGE
# nginx   k8s.io/ingress-nginx   <none>       10d
yaml
# Add annotation or ingressClassName
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx    # Older syntax
 
# OR (newer syntax)
spec:
  ingressClassName: nginx

Cause 5: NetworkPolicy Blocking Traffic

If you have NetworkPolicy enabled, Ingress traffic may be blocked.

bash
kubectl get networkpolicy -n production

Allow Ingress controller to reach your pods:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: myapp
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
    ports:
    - port: 8080

Full Fix Checklist

bash
# 1. Check pod health
kubectl get pods -n production -l app=myapp
# Look for READY: 1/1 and STATUS: Running
 
# 2. Check endpoints
kubectl get endpoints myapp-service -n production
# Should show IP addresses, not <none>
 
# 3. Check service selector matches pod labels
kubectl get svc myapp-service -n production -o yaml | grep -A 5 selector
kubectl get pods -n production -l app=myapp --show-labels
 
# 4. Test direct access to pod (bypass Ingress)
kubectl port-forward pod/myapp-xyz -n production 8080:8080
curl localhost:8080/health
# If this works, problem is between Ingress and Service
 
# 5. Test via Service (bypass Ingress)
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
  curl myapp-service.production.svc.cluster.local/health
# If this works, problem is in the Ingress config
 
# 6. Check Ingress controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100 | grep -i error

503 means no healthy backends. Start at the pod level (is it Ready?) and work up to the Service (does it have endpoints?) then the Ingress config (correct name and port?).


More Ingress fixes? Read our Nginx Ingress 502 bad gateway fix and Kubernetes service not routing traffic fix.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments