DevOpsInterviewPrep logo
← ☸️ Containers & Kubernetes
Foundational

Kubernetes Services and EndpointSlices: from stable name to ready backend

Follow a Kubernetes Service from DNS name through selectors and EndpointSlices to a backend port. Diagnose healthy Pods behind a failing Service using read-only checks.

TL;DR: A Service defines a stable way to reach a changing set of backends. For a selector-based Service, Kubernetes derives EndpointSlices from matching Pods and their status. Correct DNS, correct selection and a listening application port are independent requirements.

A name stays stable while Pods change

A Deployment rollout replaces Pods and their IP addresses. Clients need a discovery mechanism that survives those replacements. A typical ClusterIP Service provides a stable virtual IP and DNS name, while the cluster's Service data plane directs connections to eligible backends.

A Service is an API object, not a process listening inside every Pod. The forwarding implementation depends on the cluster. kube-proxy is common, and alternative network implementations can provide equivalent Service behavior. The Service documentation describes the abstraction and its types.

rendering diagram…

The EndpointSlice path configures backend knowledge; it is not an extra HTTP proxy through which every request travels. A packet's actual route depends on the installed network implementation.

Read all three port names carefully

This illustrative manifest assumes matching Pods in the same namespace listen on TCP port 8080. It does not create those Pods.

apiVersion: v1
kind: Service
metadata:
  name: checkout
  namespace: shop
spec:
  selector:
    app: checkout
  ports:
    - name: http
      port: 80
      targetPort: 8080
  type: ClusterIP

The client connects to Service port 80. The selected Pod receives the connection on port 8080. A container's containerPort declaration can document or name a port, but it does not cause the application process to listen there. The application must bind the intended address and port itself.

A named targetPort resolves through the corresponding named port in the selected Pod. This can support different numeric ports across revisions, provided each Pod declares the correct name. An absent or incorrect name can break backend routing even if the Service manifest looks reasonable.

Selectors decide membership

SymptomEvidence to inspectPossible explanation
Service exists, no backendsSelector and Pod labelsNew Deployment uses app=checkout-v2, Service expects app=checkout
Backends exist but are not readyEndpoint conditions and readiness probeStartup dependency failed or probe points at wrong endpoint
Backend IP works, Service failsService port and data-plane behaviorPort mapping or forwarding configuration is wrong
Service IP works, name failsDNS query from the affected namespaceResolver, search path or DNS policy issue
Some requests failCompare backend revisions and portsOne selected Pod has a different listener or unhealthy dependency

Service selectors normally select Pods in the Service's namespace. A similarly named Pod in another namespace is not automatically part of the backend set. Also check whether this is a selectorless Service with manually managed EndpointSlices before assuming the normal controller owns membership.

Diagnose from the client outward

These read-only checks assume the example names:

kubectl -n shop get service checkout -o yaml
kubectl -n shop get pods -l app=checkout -o wide
kubectl -n shop get endpointslices \
  -l kubernetes.io/service-name=checkout -o yaml

Inspect endpoint addresses, ports and readiness-related conditions. The EndpointSlice documentation explains how endpoint conditions represent readiness, serving and termination. Configuration such as publishNotReadyAddresses changes normal readiness expectations and should be an intentional choice.

Then reproduce the connection from a permitted diagnostic environment with the same namespace and network policy context as the failing client. A successful request from your laptop through a port-forward bypasses parts of the Service and policy path. It can establish that the application responds while leaving the original failure unexplained.

NetworkPolicy enforcement also depends on the network plugin. If direct Pod requests fail, inspect policy and actual listening behavior before changing the Service type. Exposing a LoadBalancer is not a general repair for an internal selector error.

Headless discovery changes the client contract

A headless Service sets clusterIP: None. DNS can return backend addresses instead of a single Service virtual IP, allowing clients to choose or identify individual endpoints. That is useful for some stateful systems, but it gives the client more responsibility for resolution, caching and connection behavior.

The normal ClusterIP abstraction and headless discovery are different designs. A client that resolves once and caches forever can keep sending to an obsolete Pod address. Understand DNS caching and the client's refresh behavior before relying on rapid endpoint changes.

Work the fault isolation

A correct Service can still be unreachable because NetworkPolicy restricts source egress or destination ingress. Test both directions against the selected Pods.

Self-check: all Pods show Running, the Service DNS name resolves, and requests time out. Which claim is still unproven?

Running does not establish readiness, selector membership or successful application listening. Inspect EndpointSlices, verify targetPort, and test from the failing client's network context. DNS success establishes name resolution only. A timeout can occur later in policy enforcement, forwarding, transport or application processing.

Practice a Service returning 503 with healthy Pods, then add the external routing layer in Ingress controllers and Gateway API.

RELATED CONCEPTS
PRACTICE THIS IN REAL QUESTIONS