What is Service Discovery in Kubernetes? Explained Simply (2026)
How do pods find each other in Kubernetes? Service discovery is the mechanism that lets services communicate without hardcoded IPs. Here's how it works, simply explained.
In Kubernetes, pods get new IP addresses every time they restart. If your frontend pod hardcoded the backend's IP address, it would break every time the backend restarted. Service discovery solves this — it gives services stable names so pods can find each other without knowing IPs.
The Problem Service Discovery Solves
Let's say you have a frontend app talking to a backend API. Without service discovery:
Frontend pod (IP: 10.0.0.15) → Backend pod (IP: 10.0.0.22)
Backend pod restarts → new IP: 10.0.0.47 → frontend can't find it.
With service discovery:
Frontend pod → backend.default.svc.cluster.local → (finds current backend pods)
The name stays the same. The IP lookup always returns current, healthy pod IPs.
How Kubernetes Service Discovery Works
Kubernetes uses two mechanisms:
- Services — a stable virtual IP (ClusterIP) and DNS name for a group of pods
- CoreDNS — a DNS server running inside the cluster that resolves service names to ClusterIPs
Together, they give every service a stable DNS name that works from any pod.
Step 1: Services (The Stable Endpoint)
A Service in Kubernetes is a load balancer in front of your pods. It selects pods using labels.
apiVersion: v1
kind: Service
metadata:
name: backend # Service name
namespace: default
spec:
selector:
app: backend # Select pods with this label
ports:
- port: 80 # Port the service listens on
targetPort: 8080 # Port the pods listen onWhat this creates:
- A ClusterIP (virtual IP like 10.96.0.45) — stable, doesn't change
- A DNS name:
backend.default.svc.cluster.local
Even if backend pods restart with new IPs, the Service's ClusterIP and DNS name remain the same.
Step 2: CoreDNS (The DNS Resolver)
CoreDNS is a DNS server that runs as a deployment in the kube-system namespace. Every pod in the cluster is configured to use CoreDNS as its DNS server.
# Check CoreDNS pods
kubectl get pods -n kube-system | grep coredns
# Check what DNS server pods use
kubectl exec -it mypod -- cat /etc/resolv.confOutput:
nameserver 10.96.0.10 # CoreDNS ClusterIP
search default.svc.cluster.local svc.cluster.local cluster.local
When your frontend pod does curl http://backend/api, CoreDNS resolves backend → 10.96.0.45 (the Service ClusterIP) → forwards to a backend pod.
DNS Name Format
Kubernetes services get predictable DNS names:
<service-name>.<namespace>.svc.cluster.local
Examples:
backend.default.svc.cluster.local— full namebackend.default— works within same clusterbackend— works within same namespace
Short names work because of the search domains in /etc/resolv.conf.
So from a pod in the default namespace, all of these resolve to the same service:
curl http://backend/api
curl http://backend.default/api
curl http://backend.default.svc.cluster.local/apiFrom a pod in a different namespace (e.g., frontend namespace), you need:
curl http://backend.default/api # Must specify namespaceTypes of Services
ClusterIP (default)
Only accessible inside the cluster. Used for pod-to-pod communication.
spec:
type: ClusterIP # Default — no external accessNodePort
Exposes the service on a port of every node. External traffic can reach it via <NodeIP>:<NodePort>.
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # External port (30000–32767)LoadBalancer
Provisions a cloud load balancer (AWS ALB, GCP Load Balancer) that routes to pods.
spec:
type: LoadBalancer # Creates cloud LB, gets external IPHeadless Service
Returns pod IPs directly instead of a ClusterIP. Used for stateful apps (databases) where you want to connect to a specific pod.
spec:
clusterIP: None # No virtual IP — returns pod IPs directlyReal Example: Frontend Calling Backend
# Backend deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend # Label must match Service selector
spec:
containers:
- name: backend
image: myapp/backend:latest
ports:
- containerPort: 8080
---
# Backend service
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
selector:
app: backend
ports:
- port: 80
targetPort: 8080Frontend code:
// No hardcoded IPs — use service name
const response = await fetch('http://backend/api/users')This works because:
backendresolves via CoreDNS to the Service ClusterIP- kube-proxy routes the request to one of the backend pods
- Pod restarts? Service stays, DNS stays, traffic continues
How Load Balancing Works
When a Service has multiple pod replicas, kube-proxy load balances traffic across them using iptables or IPVS rules on each node.
# See 3 backend pods
kubectl get pods -l app=backend -o wide
NAME IP
backend-abc12 10.0.1.5
backend-def45 10.0.1.6
backend-ghi78 10.0.1.7
# Service routes to all three (round-robin by default)Debugging Service Discovery
# Test DNS resolution from inside a pod
kubectl run debug --image=busybox --rm -it -- sh
nslookup backend
nslookup backend.default.svc.cluster.local
# Check if service exists and has endpoints
kubectl get service backend
kubectl get endpoints backend
# No endpoints = no matching pods (check labels)
kubectl get pods --show-labels | grep backend
# Check if pods match service selector
kubectl describe service backend | grep SelectorCommon issue: Service has no endpoints.
# Endpoints empty = selector labels don't match pod labels
kubectl get endpoints backend
# NAME ENDPOINTS AGE
# backend <none> 5m ← Problem: no pods match selectorFix: verify your pod labels match the Service's spec.selector.
Summary
| Concept | What it does |
|---|---|
| Service | Stable virtual IP + DNS name in front of pods |
| CoreDNS | DNS server inside the cluster — resolves service names |
| ClusterIP | Virtual IP that stays constant while pods change |
| DNS name | <service>.<namespace>.svc.cluster.local |
| kube-proxy | Routes traffic from Service IP to pod IPs |
Service discovery in Kubernetes is automatic — create a Service and any pod in the cluster can reach it by name.
Related: Kubernetes Network Policies Blocking Traffic Fix | Kubernetes Architecture Explained | CoreDNS Resolution Failures Fix
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
How to Migrate from Ingress-NGINX to Kubernetes Gateway API in 2026
Step-by-step guide to migrating from Ingress-NGINX to Kubernetes Gateway API. Includes YAML examples, implementation choices, testing strategy, and cutover plan.
How to Set Up Kubernetes Gateway API to Replace Ingress (2026 Guide)
The Kubernetes Ingress API is being replaced by the Gateway API. Here's a complete step-by-step guide to setting it up with Nginx Gateway Fabric and migrating from Ingress.
What is a Service Mesh? Explained Simply (No Jargon)
Service mesh sounds complicated but the concept is simple. Here's what it actually does, why teams use it, and whether you need one — explained without the buzzwords.