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 CodeResolves ToWorks When
payment-servicepayment-service.default.svc.cluster.localSame namespace
payment-service.productionpayment-service.production.svc.cluster.localAny namespace
payment-service.production.svc.cluster.localExact matchAny 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.

Leave a Comment