Kubernetes DNS and Service Discovery Inside the Cluster
When one microservice needs to reach another inside a Kubernetes cluster, it needs an address. Kubernetes runs an internal DNS server that automatically gives every Service a stable, human-readable name. Your applications never need to hardcode IP addresses — they use names that always resolve to the right Service.
What CoreDNS Does
Kubernetes runs a DNS server called CoreDNS inside the cluster. It runs as a Deployment in the kube-system namespace. Every Pod in the cluster uses CoreDNS as its DNS resolver. When a Pod looks up a Service name, CoreDNS returns the Service's ClusterIP address.
Pod needs to reach "payment-service"
↓
DNS query → CoreDNS (10.96.0.10)
↓
CoreDNS returns: 10.96.45.22 (ClusterIP of payment-service)
↓
Pod connects to 10.96.45.22:8080
The Full DNS Name Format
Every Service in Kubernetes gets a fully qualified domain name (FQDN):
<service-name>.<namespace>.svc.cluster.local
Examples:
payment-service.default.svc.cluster.local user-api.production.svc.cluster.local mysql-0.mysql.staging.svc.cluster.local ← StatefulSet Pod
Short Name Resolution
You do not always need to type the full FQDN. Kubernetes configures each Pod's DNS search domains so shorter names work for same-namespace lookups:
| Name Used in Code | Resolves To | Works When |
|---|---|---|
payment-service | payment-service.default.svc.cluster.local | Same namespace |
payment-service.production | payment-service.production.svc.cluster.local | Any namespace |
payment-service.production.svc.cluster.local | Exact match | Any namespace |
Verifying DNS from Inside a Pod
Open a shell in any running Pod and use standard DNS tools:
kubectl exec -it my-pod -- /bin/sh # Inside the pod: nslookup payment-service nslookup payment-service.production.svc.cluster.local curl http://payment-service:8080/health
If DNS is not resolving, check whether CoreDNS Pods are healthy:
kubectl get pods -n kube-system -l k8s-app=kube-dns kubectl logs -n kube-system -l k8s-app=kube-dns
How Pods Get Their DNS Configuration
When Kubernetes starts a Pod, it injects a /etc/resolv.conf file into the container. This file points to CoreDNS and sets up search domains for short-name resolution:
# /etc/resolv.conf inside a Pod (auto-generated) nameserver 10.96.0.10 # CoreDNS ClusterIP search default.svc.cluster.local svc.cluster.local cluster.local options ndots:5
Service Discovery Patterns in Microservices
Microservices use DNS-based service discovery to find each other without any external service registry or hardcoded addresses.
Order Service Payment Service
┌──────────────────┐ ┌─────────────────────┐
│ POST /checkout │ │ POST /charge │
│ │────────►│ payment-service:8080│
│ calls: │ └─────────────────────┘
│ http://payment- │
│ service:8080/ │ Database
│ charge │ ┌─────────────────────┐
│ │────────►│ postgres.default │
└──────────────────┘ │ :5432 │
└─────────────────────┘
Each service name is just a Kubernetes Service backed by real Pods. The DNS layer hides all the Pod IP complexity.
Headless Services and Per-Pod DNS
For StatefulSets, a Headless Service (clusterIP: None) creates DNS records for individual Pods, not just the Service:
Headless Service: mysql (clusterIP: None) StatefulSet: mysql with 3 replicas DNS records created: mysql.default.svc.cluster.local → returns IPs of all Pods mysql-0.mysql.default.svc.cluster.local → returns IP of Pod 0 mysql-1.mysql.default.svc.cluster.local → returns IP of Pod 1 mysql-2.mysql.default.svc.cluster.local → returns IP of Pod 2
Your application connects to mysql-0 to reach the primary directly, or queries the headless Service name to get all Pod IPs for client-side load balancing.
External DNS: Publishing Cluster Services Outside
The ExternalDNS add-on watches Services and Ingress resources in your cluster and automatically creates DNS records in your cloud DNS provider (Route53, Google Cloud DNS, Azure DNS). When you create a LoadBalancer Service with a hostname annotation, ExternalDNS creates the public DNS record without any manual step.
LoadBalancer Service created with annotation:
external-dns.alpha.kubernetes.io/hostname: shop.example.com
ExternalDNS detects it
↓
Creates DNS A record: shop.example.com → 34.120.45.100
DNS Customization with CoreDNS ConfigMap
CoreDNS reads its configuration from a ConfigMap in the kube-system namespace. You can add custom DNS rules — for example, resolve an internal hostname to a specific IP or forward queries for a specific domain to an external DNS server:
kubectl edit configmap coredns -n kube-system
Add a custom host entry or a forwarding rule carefully — mistakes here break DNS for the entire cluster.
Key Points
- CoreDNS runs inside the cluster and gives every Service a stable DNS name automatically.
- The full DNS format is
<service>.<namespace>.svc.cluster.local— short names work within the same namespace. - Kubernetes injects DNS configuration into every Pod via
/etc/resolv.conf. - Headless Services create per-Pod DNS records for direct StatefulSet Pod addressing.
- ExternalDNS automates public DNS record creation when you expose Services with cloud load balancers.
