Skip to content
Control Plane Labs

Kubernetes Service No Endpoints: Debug Checklist

Fix a Kubernetes Service with no endpoints: check EndpointSlices, selectors, readiness, targetPort, terminating Pods, and selectorless Services in order.

Ben Ennis

Published October 6, 2026

A Service with no endpoints fails quietly. The ClusterIP still exists, DNS still resolves, and the Deployment can report every replica as Running. Clients see refused connections, timeouts, or a 503 from the edge. The Kubernetes Service debugging guide treats an empty ENDPOINTS column as its own branch of the investigation, and it deserves one, because the fix almost never lives in the Service’s networking. It lives in labels, readiness, or ports.

Where Kubernetes records a Service’s endpoints

A control loop evaluates every Service selector and writes the result into one or more EndpointSlice objects. The EndpointSlice documentation explains that the label kubernetes.io/service-name links each slice to its Service. By default a slice holds no more than 100 endpoints, and the --max-endpoints-per-slice controller flag can raise that to 1,000. Dual-stack Services get separate IPv4 and IPv6 slices, so never assume a slice name. Always list slices by label:

kubectl get endpointslices -n shop -l kubernetes.io/service-name=checkout

The older Endpoints API still answers, but it is not the source of truth any more. Kubernetes deprecated v1 Endpoints in v1.33, and the API server now warns anyone who reads or writes it. If a runbook or script still uses kubectl get endpoints, switch it to EndpointSlices before you trust its output during an incident.

Each endpoint in a slice carries three conditions, defined in the EndpointSlice API reference:

Condition What it means for a Pod-backed endpoint How proxies use it
serving Mirrors the Pod’s Ready condition Target for traffic, including during drain
terminating Set once the Pod has a deletion timestamp Normally ignored; used only if every endpoint is terminating
ready Shortcut for serving and not terminating The normal routing signal

“No endpoints” therefore has two forms. Either the slice is empty, or it lists addresses whose ready condition is false. The default kubectl get table does not show conditions, so read them directly:

kubectl get endpointslices -n shop -l kubernetes.io/service-name=checkout -o json \
  | jq -r '.items[].endpoints[]? | [.addresses[0], .targetRef.name,
      (.conditions.ready|tostring), (.conditions.serving|tostring),
      (.conditions.terminating|tostring)] | @tsv'

An empty result means the selector or the Service type is the problem. Rows that show false mean the Pods are matched but are not eligible for traffic.

Branch 1: the selector matches nothing

This is the most common cause, and the debugging guide calls it out by name: a Service that selects app=hostnames while the Deployment labels its Pods run=hostnames. Compare the two directly instead of reading YAML by eye:

kubectl get svc checkout -n shop -o jsonpath='{.spec.selector}'; echo
kubectl get pods -n shop -l app=checkout,tier=api --show-labels

Every key in the selector must match, so one extra key (tier: api on the Service but not on the Pod template) empties the slice as surely as a typo. Namespaces matter too. A Service only selects Pods in its own namespace, so a Deployment applied to default by mistake leaves the shop Service empty. Look for these patterns:

  • A label renamed in the Pod template during a Helm or Kustomize refactor while the Service kept the old key.
  • A canary or blue/green label (track: stable) added to the Service selector before any Pod carries it.
  • A kubectl label hotfix on running Pods that the next rollout silently reverted.

Validate both manifests in the Kubernetes YAML linter before you apply the fix, so a quoted value or an indentation slip doesn’t create a new mismatch.

Branch 2: the Pods match but are not Ready

When the slice lists addresses with ready: false, Kubernetes is doing its job. The Pod lifecycle documentation says that a failing readiness probe takes the Pod out of every matching Service’s endpoints, and that probes keep running for the container’s whole life. A dependency outage can therefore empty a Service minutes after a healthy rollout.

Readiness gates add a second way to get stuck. A Pod with readinessGates is Ready only when all of its containers are ready and every listed condition is True. A condition missing from status.conditions counts as False. If the controller that is supposed to set the gate (often a load-balancer controller) is down or misconfigured, every Pod stays at ContainersReady and never reaches Ready. Check both:

kubectl get pod checkout-7d9c-abcde -n shop \
  -o jsonpath='{range .status.conditions[*]}{.type}={.status}{"\n"}{end}'
kubectl describe pod checkout-7d9c-abcde -n shop | sed -n '/Events/,$p'

For probe-level fixes (paths, ports, timing, and dependency checks), follow the readiness probe debugging guide and the probe configuration reference. Do not “fix” this branch by loosening readiness until the probe passes. That moves the failure from an empty Service to errors returned to users.

publishNotReadyAddresses: true is the one deliberate exception. The Service API reference says controllers then treat every endpoint as ready, even when the Pods are not. Its intended use is a StatefulSet’s headless Service that publishes peer DNS records during bootstrap. On an ordinary ClusterIP Service it hides exactly the signal you are looking for.

Branch 3: endpoints exist but connections still fail

If the slice shows ready addresses and clients still fail, check ports before networking. The Service’s targetPort is a number or a name. A name is looked up in each target Pod’s container ports, and if targetPort is omitted it defaults to port. The debugging guide lists the traps: the Service port is not in spec.ports[], the number was written as the string "9376", a named port doesn’t exist on the Pod, or the protocol is wrong.

Named ports also explain a confusing rollout state. All endpoints in one slice must share the same ports, so a rollout that moves a named port from 80 to 8080 can briefly leave the Service with two slices. That is normal. Test the Pods directly on the Pod port, not the Service port:

kubectl run probe --rm -it --image=busybox:1.36 -n shop -- \
  wget -qO- -T 3 http://10.244.0.5:8080/healthz

If the direct test works but the ClusterIP doesn’t, look at the proxy layer: kube-proxy logs, then rules with iptables-save or ipvsadm -ln, as described in the virtual IPs reference. A NetworkPolicy that denies ingress to the Pods produces the same symptom but leaves the endpoints intact. A DNS lookup that returns the wrong ClusterIP points to a client in the wrong namespace.

Branch 4: selectorless Services and terminating Pods

A Service with no selector never gets automatic endpoints. The Service concepts page describes this pattern for backends outside the cluster or in another namespace. You create EndpointSlices yourself and link them with the kubernetes.io/service-name label. Manually listed IPs cannot be loopback, link-local, or another Service’s ClusterIP. If a selectorless Service is empty, something that used to populate it (an operator, a sync job, or a Terraform module) has stopped. Find that owner. Don’t add a selector as a quick fix.

During a rollout or node drain, the slice may list endpoints with terminating: true. Those endpoints always report ready: false for backward compatibility. Proxies normally skip them, but if every endpoint is terminating, proxies may route to endpoints that are both serving and terminating, so in-flight traffic can drain. A Service that only goes empty during deploys usually means maxUnavailable, PodDisruptionBudgets, or preStop timing let every old Pod start terminating before a new Pod became Ready.

A ten-minute no-endpoints checklist

  1. List slices by label: kubectl get endpointslices -l kubernetes.io/service-name=<svc>. Empty means branch 1 or 4; addresses listed means branch 2 or 3.
  2. Print the Service selector and run it as a Pod label query in the same namespace. Fix the label at its source (chart or overlay), not with kubectl label.
  3. Read each endpoint’s ready, serving, and terminating conditions with the jq filter above.
  4. For not-ready Pods, read Pod conditions and events, and check readiness gates before you touch the probe.
  5. Confirm targetPort resolves to a real container port and protocol, then test one Pod IP directly.
  6. If the Pod test passes but the ClusterIP fails, check NetworkPolicy, then kube-proxy rules.
  7. Retire any kubectl get endpoints checks in runbooks and dashboards in favor of EndpointSlices.

Frequently asked questions

Why does my Kubernetes Service show no endpoints when the Pods are Running?+
Running is not Ready. Either the Service selector matches no Pod labels, or the matched Pods have a failing readiness probe or an unmet readiness gate. Check the EndpointSlice conditions and the Pod's Ready condition.
Should I use kubectl get endpoints or kubectl get endpointslices?+
Use EndpointSlices. The v1 Endpoints API has been deprecated since Kubernetes v1.33, and the API server returns a warning when you read it. List slices with the kubernetes.io/service-name label.
What does ready: false mean in an EndpointSlice?+
The endpoint is either not serving, meaning the Pod is not Ready, or it is terminating. Proxies skip it for normal traffic. Check the serving and terminating conditions to tell the two cases apart.
Can a Service select Pods in another namespace?+
No. A selector only matches Pods in the Service's own namespace. To reach backends elsewhere, use a selectorless Service with manually managed EndpointSlices, or an ExternalName Service.
Is publishNotReadyAddresses a safe fix for an empty Service?+
No. It makes controllers treat every endpoint as ready, so traffic reaches Pods that have not passed readiness. Its intended use is peer discovery through a StatefulSet's headless Service.
Why does my Service go empty only during deployments?+
Every old Pod was terminating before a new Pod became Ready. Review maxUnavailable, PodDisruptionBudgets, startup and readiness probe timing, and preStop hooks so at least one Ready endpoint remains.

Tags: #kubernetes, #services, #endpointslices, #networking, #debugging