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
$ 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.
$ 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.
$ 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.
$ kubectl patch service web --type=merge -p '{"spec":{"selector":{"app":"web"}}}'
service/web patched
For source-controlled workloads, make the same selector change in the Service manifest or Helm values so the fix survives the next apply.
$ 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
$ 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.
$ 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.
^C