6.9 Service, Endpoint & Ingress Connectivity Troubleshooting
Key Takeaways
- Kubernetes Service routing depends on accurate label selector matching; if a Service's 'spec.selector' does not match the target Pod's 'metadata.labels', no Endpoints or EndpointSlices will be populated (Endpoints will show '<none>').
- A Pod will be omitted from Service Endpoints even if labels match if the Pod's readinessProbe is failing or if the Pod is not in the 'Running' phase.
- Port mapping mismatches are a frequent source of connectivity failures: 'spec.ports[].port' is the external port exposed by the Service, while 'spec.ports[].targetPort' must match the container's active listening port.
- Ingress routing failures occur due to missing IngressClasses, path routing mismatches (Prefix vs Exact vs ImplementationSpecific), rewrite annotation omissions, or backend Service name/port discrepancies.
- Systematic network debugging utilizes interactive test pods ('kubectl run tmp-shell --rm -it --image=busybox:1.36') to execute 'nslookup', 'nc -zv', and 'curl' across every hop of the network path.
6.9 Service, Endpoint & Ingress Connectivity Troubleshooting
Networking in Kubernetes operates across multiple virtual layers: container virtual ethernet pairs (veth), CNI flat routing, virtual ClusterIP load-balancing via kube-proxy, cluster-internal DNS resolution via CoreDNS, and HTTP/HTTPS layer 7 ingress routing.
When a client or frontend microservice cannot communicate with a backend service, administrators must isolate the exact hop where traffic is dropped.
1. End-to-End Traffic Path & Hop-by-Hop Triage
+-----------------------------------------------------------------------------------------+
| END-TO-END SERVICE TRAFFIC PIPELINE |
| |
| [CLIENT POD] |
| | |
| v (1. Resolves DNS: backend-svc.default.svc.cluster.local -> 10.96.0.50) |
| [CoreDNS] |
| | |
| v (2. Sends packet to ClusterIP 10.96.0.50:80) |
| [KUBE-PROXY / IPTABLES / IPVS on Host Kernel] |
| - Matches DNAT rule for 10.96.0.50:80 |
| - Randomly selects backend Pod IP from Endpoints / EndpointSlices (e.g., 10.244.1.25) |
| - Rewrites destination IP to 10.244.1.25:8080 (targetPort) |
| | |
| v (3. CNI Routes packet across node network overlay) |
| [TARGET BACKEND POD (10.244.1.25)] |
| - Listens on container port 8080 |
| - Readiness probe must be PASSING (otherwise omitted from Endpoints) |
+-----------------------------------------------------------------------------------------+
2. Service & Endpoints Diagnostic Checklist
When a ClusterIP or NodePort Service fails to route traffic, execute this sequential 5-step checklist:
# Step 1: Verify the Service exists and has an assigned ClusterIP
kubectl get svc backend-svc
# Step 2: Check if Endpoints and EndpointSlices exist for the service
kubectl get endpoints backend-svc
kubectl get endpointslices -l kubernetes.io/service-name=backend-svc
Case A: Endpoints displays <none>
If kubectl get endpoints backend-svc shows ENDPOINTS: <none>, traffic cannot be routed because the Service has zero healthy backend pods.
[TROUBLESHOOTING ZERO ENDPOINTS]
1. Check Service Selector: $ kubectl get svc backend-svc -o jsonpath='{.spec.selector}'
Output: map[app:web-backend env:prod]
2. Check Pod Labels: $ kubectl get pods --show-labels
Output: pod-1: app=web-backend, env=production <-- MISMATCH! (prod vs production)
3. Check Pod Health: $ kubectl get pods -l app=web-backend
- If Pods are Running but 0/1 Ready -> Readiness probe is failing!
[!IMPORTANT] A pod is added to an
Endpointsobject only if:
- All key-value pairs in
service.spec.selectormatch the pod'smetadata.labels.- The pod is in the
Runningphase.- The pod's
readinessProbeis succeeding (or no readiness probe is configured).
Case B: Endpoints Populated, But Connection Refused / Times Out
If endpoints exist (e.g., 10.244.1.25:8080), but curling the ClusterIP fails:
# Verify port mapping configuration in Service spec
kubectl get svc backend-svc -o yaml
spec:
ports:
- name: http
port: 80 # Port exposed on the Service ClusterIP
targetPort: 8080 # Port where application container actually listens
protocol: TCP
- TargetPort Mismatch: If the application inside the container listens on port
3000, buttargetPortis set to8080, packets reach the pod but the Linux kernel returns TCP RST (Connection Refused). - Named Port Typo: If
targetPort: http-webis used, ensure the container spec containsports: [{name: http-web, containerPort: 8080}].
3. Ingress Routing & Controller Diagnostics
An Ingress resource is merely a set of rules; traffic routing requires an active Ingress Controller (e.g., ingress-nginx).
+-----------------------------------------------------------------------------------------+
| INGRESS ARCHITECTURAL FLOW |
| |
| External Client ---> [Ingress Controller (e.g., NGINX Pod / NodePort / LB)] |
| | |
| +---> Evaluates Host: app.example.com |
| +---> Evaluates Path: /api (Prefix matching) |
| | |
| v (Routes directly to Pod IPs from Endpoints) |
| [Backend Pods] |
+-----------------------------------------------------------------------------------------+
High-Frequency Ingress Issues & Solutions:
-
Missing or Mismatched
ingressClassName:spec: ingressClassName: nginx # Must match an existing IngressClass: kubectl get ingressclass -
Path Type Matching (
PrefixvsExact):pathType: Exactmatching/apiwill NOT match/api/v1/users.- Use
pathType: Prefixwithpath: /api.
-
Rewrite Annotation Omission: If incoming traffic hits
app.example.com/api/users, but the backend application expects requests at/users, include the NGINX rewrite annotation:metadata: annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: rules: - host: app.example.com http: paths: - path: /api(/|$)(.*) pathType: ImplementationSpecific backend: service: name: backend-svc port: number: 80 -
Inspect Ingress Controller Logs:
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100
4. In-Cluster Connectivity Debugging Runbook
To prove whether a failure is DNS-related, Service-related, or container-related, run a temporary interactive test container:
# 1. Launch a temporary debugging pod
kubectl run tmp-net --rm -it --image=busybox:1.36 --restart=Never -- /bin/sh
# --- Inside the test container shell ---
# 2. Test DNS resolution of the service name
nslookup backend-svc
nslookup backend-svc.default.svc.cluster.local
# 3. Test TCP port reachability on ClusterIP
nc -zv 10.96.0.50 80
# 4. Test HTTP payload response
wget -qO- http://backend-svc:80/healthz
# 5. Test direct Pod IP connectivity (Bypassing Service layer)
# Retrieve Pod IP: kubectl get pods -l app=backend -o wide
wget -qO- http://10.244.1.25:8080/healthz
A developer creates a Service named auth-api to expose a deployment. However, running kubectl get endpoints auth-api displays ENDPOINTS: <none>. The administrator verifies that 3 deployment pods exist and are in the Running phase. What is the most probable cause of this issue?
An administrator is inspecting a Service definition with the following configuration:
When curling the Service ClusterIP on port 80 from inside a test pod, the connection is instantly rejected with spec:
ports:
- port: 80
targetPort: 8080
Connection refused. Direct curl requests to the target pod IP on port 3000 succeed. What is the root cause?
An Ingress resource configured for host: portal.example.com with path: /store returns HTTP 404 Not Found from the Ingress Controller when users access http://portal.example.com/store/products. The backend service functions properly when queried directly. What configuration error is present in the Ingress resource?