What DNS Records Does a Headless Service Create?

intermediate|dnsdevopssrebackend developerCKACKAD
TL;DR

A Headless Service (clusterIP: None) creates DNS A records that return individual Pod IPs instead of a single ClusterIP. For StatefulSets, it also creates per-Pod A records in the format <pod-name>.<service-name>.<namespace>.svc.cluster.local, enabling direct Pod addressing.

Detailed Answer

A Headless Service is a Service with clusterIP: None. Instead of routing through a virtual IP, it exposes individual Pod IPs directly through DNS. This is essential for stateful workloads and peer discovery.

Regular Service vs Headless Service DNS

Regular Service (ClusterIP)

apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: default
spec:
  selector:
    app: web
  ports:
    - port: 80

DNS lookup returns one IP (the ClusterIP):

nslookup web.default.svc.cluster.local
# Name: web.default.svc.cluster.local
# Address: 10.96.45.12    ← Single ClusterIP

Headless Service

apiVersion: v1
kind: Service
metadata:
  name: web-headless
  namespace: default
spec:
  clusterIP: None
  selector:
    app: web
  ports:
    - port: 80

DNS lookup returns all Pod IPs:

nslookup web-headless.default.svc.cluster.local
# Name: web-headless.default.svc.cluster.local
# Address: 10.244.1.5     ← Pod 1 IP
# Address: 10.244.2.8     ← Pod 2 IP
# Address: 10.244.3.3     ← Pod 3 IP

StatefulSet Per-Pod DNS Records

When a Headless Service is used with a StatefulSet, each Pod gets its own addressable DNS record:

apiVersion: v1
kind: Service
metadata:
  name: redis-headless
  namespace: cache
spec:
  clusterIP: None
  selector:
    app: redis
  ports:
    - port: 6379
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  namespace: cache
spec:
  serviceName: "redis-headless"    # Links to the Headless Service
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:7.2
          ports:
            - containerPort: 6379
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"

DNS records created:

# Aggregate record (all Pods)
redis-headless.cache.svc.cluster.local → 10.244.1.5, 10.244.2.8, 10.244.3.3

# Per-Pod records (StatefulSet only)
redis-0.redis-headless.cache.svc.cluster.local → 10.244.1.5
redis-1.redis-headless.cache.svc.cluster.local → 10.244.2.8
redis-2.redis-headless.cache.svc.cluster.local → 10.244.3.3

SRV Records

Headless Services also create SRV records for service discovery:

dig SRV redis-headless.cache.svc.cluster.local

# _tcp.redis-headless.cache.svc.cluster.local. SRV 0 33 6379 redis-0.redis-headless.cache.svc.cluster.local.
# _tcp.redis-headless.cache.svc.cluster.local. SRV 0 33 6379 redis-1.redis-headless.cache.svc.cluster.local.
# _tcp.redis-headless.cache.svc.cluster.local. SRV 0 33 6379 redis-2.redis-headless.cache.svc.cluster.local.

SRV records include the port number, useful for services that use dynamic ports.

publishNotReadyAddresses

By default, only Pods with a Ready status are included in DNS. For some use cases (like peer discovery during initialization), you need unready Pods included:

apiVersion: v1
kind: Service
metadata:
  name: redis-headless
spec:
  clusterIP: None
  publishNotReadyAddresses: true    # Include not-ready Pods in DNS
  selector:
    app: redis
  ports:
    - port: 6379

This is important for StatefulSets where Pod-1 needs to find Pod-0's address even before Pod-0 passes its readiness probe (e.g., during cluster bootstrapping).

Use Cases for Headless Service DNS

| Use Case | Why Headless DNS | |---|---| | Database replication | Replicas need to find the primary by name | | Kafka brokers | Consumers need to connect to specific brokers | | etcd cluster | Members need to discover peers during bootstrap | | Elasticsearch | Nodes use DNS for cluster formation | | Client-side load balancing | gRPC clients want all endpoints to load balance themselves |

Headless Service with Deployments

Headless Services work with Deployments, but you only get the aggregate DNS record:

# Deployment Pods get random names — no per-Pod records
nslookup web-headless.default.svc.cluster.local
# Address: 10.244.1.5
# Address: 10.244.2.8
# Address: 10.244.3.3

# No per-Pod records like web-abc12.web-headless...
# Per-Pod DNS only works with StatefulSets

This is still useful for gRPC clients that need to discover all endpoints for client-side load balancing, since gRPC's long-lived connections bypass ClusterIP round-robin.

Verifying DNS Records

# From a debug Pod
kubectl run dns-test --rm -it --image=busybox -- sh

# Look up the Headless Service
nslookup redis-headless.cache.svc.cluster.local

# Look up a specific Pod
nslookup redis-0.redis-headless.cache.svc.cluster.local

# Check SRV records
nslookup -type=SRV redis-headless.cache.svc.cluster.local

Why Interviewers Ask This

Interviewers ask this to test your understanding of how DNS-based service discovery works for stateful workloads and peer-to-peer communication patterns.

Common Follow-Up Questions

What is the difference between a Headless Service DNS response and a regular Service DNS response?
A regular Service returns a single ClusterIP. A Headless Service returns multiple A records — one for each ready Pod IP. This enables client-side load balancing or direct Pod selection.
Do Headless Services work with Deployments?
Yes, but you only get the aggregate DNS record returning all Pod IPs. Per-Pod DNS records (<pod-name>.<service>) only work with StatefulSets.
What happens to DNS records when a Pod is not Ready?
By default, only Ready Pods are included in DNS responses. You can change this with publishNotReadyAddresses: true on the Service.

Key Takeaways

  • Headless Services return Pod IPs directly in DNS, enabling client-side load balancing.
  • StatefulSets with Headless Services get per-Pod DNS records for individual addressing.
  • publishNotReadyAddresses controls whether unready Pods are included in DNS.

Related Questions

You Might Also Like