πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Networking intermediate ⏱ 10 minutes K8s 1.28+

K8s EndpointSlice and Service Discovery

Understand Kubernetes EndpointSlice for scalable service discovery. DNS resolution, headless services, external services, and endpoint conditions.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: EndpointSlices are the scalable replacement for Endpoints objects. Each slice holds up to 100 endpoints, enabling efficient updates in large clusters. Kubernetes auto-creates them for Services. For service discovery: my-svc.my-ns.svc.cluster.local resolves to the ClusterIP. Headless services (clusterIP: None) return individual pod IPs. Use ExternalName services to alias external DNS.

The Problem

Service discovery in Kubernetes needs to:

  • Route traffic to healthy pod backends
  • Scale to thousands of endpoints without API pressure
  • Support both internal and external service resolution
  • Handle pod lifecycle (ready/not-ready/terminating)

Old Endpoints objects stored ALL backends in one resource β€” updating one pod modified the entire object.

The Solution

How Service Discovery Works

Pod β†’ DNS Query β†’ CoreDNS β†’ Service β†’ EndpointSlice β†’ Pod IPs

DNS Resolution:
  <service>.<namespace>.svc.cluster.local β†’ ClusterIP
  
  Example:
  my-api.production.svc.cluster.local β†’ 10.96.23.45

Short names (within same namespace):
  my-api β†’ 10.96.23.45
  my-api.production β†’ 10.96.23.45

View EndpointSlices

# List EndpointSlices for a service
kubectl get endpointslices -l kubernetes.io/service-name=my-api

# Detailed view
kubectl describe endpointslice my-api-xxxxx
# Endpoints:
#   - Addresses: 10.244.1.5
#     Conditions:
#       Ready: true
#       Serving: true
#       Terminating: false
#     TargetRef: Pod/my-api-abc123
#     NodeName: worker-1
#     Zone: us-east-1a

# JSON query for ready endpoints
kubectl get endpointslice -l kubernetes.io/service-name=my-api \
  -o jsonpath='{.items[*].endpoints[?(@.conditions.ready==true)].addresses}'

Service Types and DNS

# ClusterIP (default) β€” internal DNS
apiVersion: v1
kind: Service
metadata:
  name: backend
  namespace: production
spec:
  selector:
    app: backend
  ports:
  - port: 8080
    targetPort: 8080
# DNS: backend.production.svc.cluster.local β†’ ClusterIP

---
# Headless β€” returns pod IPs directly
apiVersion: v1
kind: Service
metadata:
  name: db
spec:
  clusterIP: None           # Headless
  selector:
    app: postgres
  ports:
  - port: 5432
# DNS: db.production.svc.cluster.local β†’ [pod-ip-1, pod-ip-2, ...]
# Per-pod: postgres-0.db.production.svc.cluster.local β†’ pod-ip

---
# ExternalName β€” alias for external DNS
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: db.example.com
# DNS: external-db.production.svc.cluster.local β†’ CNAME db.example.com

---
# Service without selector β€” manual endpoints
apiVersion: v1
kind: Service
metadata:
  name: legacy-api
spec:
  ports:
  - port: 443
    targetPort: 443
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: legacy-api-manual
  labels:
    kubernetes.io/service-name: legacy-api
addressType: IPv4
ports:
- port: 443
  protocol: TCP
endpoints:
- addresses:
  - "203.0.113.10"
  - "203.0.113.11"

SRV Records

# SRV records for named ports
# _<port-name>._<protocol>.<service>.<namespace>.svc.cluster.local

# Service with named port:
# ports:
# - name: http
#   port: 8080

# SRV lookup:
dig _http._tcp.backend.production.svc.cluster.local SRV
# Returns: priority, weight, port, target
# 0 50 8080 backend.production.svc.cluster.local

Endpoint Conditions

Ready: true        β†’ Pod passed readiness probe, receives traffic
Serving: true      β†’ Pod can serve (even during termination)
Terminating: true  β†’ Pod is shutting down

Combinations:
Ready=true,  Terminating=false β†’ Normal, serving traffic
Ready=false, Terminating=false β†’ Not ready, excluded from traffic
Ready=false, Terminating=true  β†’ Shutting down, no traffic
Serving=true, Terminating=true β†’ Draining connections (graceful shutdown)

Topology-Aware Routing

# Prefer same-zone endpoints (reduces cross-zone traffic)
apiVersion: v1
kind: Service
metadata:
  name: backend
  annotations:
    service.kubernetes.io/topology-mode: Auto
spec:
  selector:
    app: backend
  ports:
  - port: 8080

# With topology-mode: Auto
# Traffic from zone-a preferentially routes to backends in zone-a
# Falls back to other zones if zone-a has insufficient capacity

Common Issues

Service returns no endpoints

Labels don’t match. Check: kubectl get pods -l <selector> vs kubectl get svc <name> -o yaml | grep selector.

Stale endpoints after pod deletion

EndpointSlice controller runs asynchronously. Takes a few seconds to update. Configure readiness probe for accurate health.

Cross-namespace service discovery

Use FQDN: <service>.<namespace>.svc.cluster.local. Short names only work within the same namespace.

Best Practices

  • Use Service DNS names β€” not pod IPs (pods are ephemeral)
  • Headless Services for StatefulSets β€” stable per-pod DNS
  • ExternalName for external service abstraction β€” swap backends without app changes
  • Set readiness probes β€” controls when pods enter EndpointSlices
  • Topology-aware routing β€” reduce cross-zone network costs

Key Takeaways

  • EndpointSlices are the scalable backend for Kubernetes service discovery
  • Services get DNS: <name>.<namespace>.svc.cluster.local
  • Headless Services (clusterIP: None) return individual pod IPs
  • ExternalName Services alias external DNS names
  • Topology-aware routing keeps traffic in the same zone
#endpointslice #service-discovery #dns #networking #cka
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens