A Kubernetes Service can keep its ClusterIP and DNS name even when no backend pod can receive traffic. When requests to a Service fail, hang, or refuse a kubectl port-forward test, start by proving whether the Service has selected ready pods and published them through EndpointSlices.
Service routing depends on three connected pieces. The selector on the Service must match pod labels, the Service port and targetPort must lead to the container listener, and the selected pods must be ready enough to appear as endpoints. A mismatch in any layer leaves ClusterIP, NodePort, LoadBalancer, and port-forward paths without a usable backend.
One common Service failure has web selecting app=api while the running backend pod is labeled app=web. Replace web and any namespace options with the affected Service, then apply only the correction that matches the workload that should receive traffic.
Related: How to create a Kubernetes Service
Related: How to check Kubernetes events
Steps to troubleshoot a Kubernetes Service:
- Inspect the Service selector, ports, and endpoint summary.
$ kubectl describe service web Name: web Namespace: default Labels: app=web Annotations: <none> Selector: app=api Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.186.225 IPs: 10.96.186.225 Port: <unset> 80/TCP TargetPort: 8080/TCP Endpoints: Session Affinity: None Internal Traffic Policy: Cluster Events: <none>
Add --namespace app when the Service is not in the current namespace. The empty Endpoints line means no selected ready backend is available for this Service.
- Compare the Service selector with pod labels in the same namespace.
$ kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS web-7897fdff9-dp5sl 1/1 Running 0 2m16s app=web,pod-template-hash=7897fdff9
The Service selector app=api does not match the backend pod label app=web. Patch or update only the intended Service; a broad selector can send traffic to unrelated pods.
- Check the Service EndpointSlice records.
$ kubectl get endpointslice -l kubernetes.io/service-name=web NAME ADDRESSTYPE PORTS ENDPOINTS AGE web-82d9s IPv4 <unset> <unset> 2m8s
EndpointSlices are the current Service backend records. A row with ENDPOINTS set to <unset> usually points to a selector, readiness, or target-port problem.
- Correct the Service selector to match the intended backend pods.
$ kubectl patch service web --type=merge -p '{"spec":{"selector":{"app":"web"}}}' service/web patchedFor source-controlled workloads, make the same selector change in the Service manifest or Helm values so the fix survives the next apply.
- Confirm that the EndpointSlice now has a backend address and port.
$ kubectl get endpointslice -l kubernetes.io/service-name=web NAME ADDRESSTYPE PORTS ENDPOINTS AGE web-82d9s IPv4 8080 10.244.0.5 2m8s
If endpoints appear but traffic still fails, compare the Service targetPort with the container listener and check the backend pod logs.
Related: How to view Kubernetes pod logs
- Start a temporary Service port-forward.
$ kubectl port-forward service/web 18080:80 Forwarding from 127.0.0.1:18080 -> 8080 Forwarding from [::1]:18080 -> 8080 Handling connection for 18080
18080:80 maps local port 18080 to Service port 80. Keep this terminal open while testing.
- Request the Service through the forwarded local port from another terminal.
$ curl --silent http://127.0.0.1:18080/ NOW: 2026-06-26 13:28:09 +0000 UTC
A backend response proves the Service selector, EndpointSlice, target port, and selected pod path are working for this Service.
- Stop the temporary port-forward session.
^C
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.