Why Do StatefulSets Need a Headless Service?

intermediate|statefulsetsdevopssrebackend developerCKACKAD
TL;DR

A Headless Service (clusterIP: None) gives each StatefulSet Pod a stable DNS record in the form <pod-name>.<service-name>.<namespace>.svc.cluster.local. This is required because StatefulSet Pods need individually addressable, stable network identities.

Detailed Answer

A Headless Service is a Service with clusterIP: None. Instead of providing a single virtual IP that load-balances across Pods, it creates individual DNS records for each Pod. StatefulSets require a Headless Service because each Pod needs a stable, unique network identity.

Why Regular Services Are Not Enough

A regular ClusterIP Service gives you a single DNS entry (e.g., mysql.default.svc.cluster.local) that round-robins across all backend Pods. This is perfect for stateless apps but breaks stateful ones:

  • A Kafka consumer needs to connect to a specific broker
  • A MySQL replica needs to find the primary by hostname
  • An etcd member must announce its own address to the cluster

Creating a Headless Service

apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
  labels:
    app: mysql
spec:
  clusterIP: None
  selector:
    app: mysql
  ports:
    - port: 3306
      targetPort: 3306

The key is clusterIP: None. This tells Kubernetes not to allocate a virtual IP and instead return the Pod IPs directly in DNS responses.

How DNS Records Work

With a StatefulSet named mysql and a Headless Service named mysql-headless in the default namespace, Kubernetes creates:

Per-Pod A records:

mysql-0.mysql-headless.default.svc.cluster.local → 10.244.1.5
mysql-1.mysql-headless.default.svc.cluster.local → 10.244.2.8
mysql-2.mysql-headless.default.svc.cluster.local → 10.244.3.3

Service-level A record (returns all Pod IPs):

mysql-headless.default.svc.cluster.local → 10.244.1.5, 10.244.2.8, 10.244.3.3

SRV records:

_tcp.mysql-headless.default.svc.cluster.local → mysql-0, mysql-1, mysql-2

Linking the StatefulSet to the Service

The StatefulSet references the Headless Service via the serviceName field:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: "mysql-headless"   # Must match the Headless Service name
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          ports:
            - containerPort: 3306
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"
            limits:
              cpu: "1"
              memory: "1Gi"

Common Pattern: Two Services

In production, you often create two Services for a StatefulSet:

  1. Headless Service — for peer discovery and the serviceName field
  2. Regular ClusterIP Service — for client connections that should be load-balanced
# Headless Service for peer discovery
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
spec:
  clusterIP: None
  selector:
    app: mysql
  ports:
    - port: 3306
---
# Regular Service for client access
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  selector:
    app: mysql
  ports:
    - port: 3306
      targetPort: 3306

Clients connect to mysql.default.svc.cluster.local for load-balanced access, while replicas use mysql-0.mysql-headless.default.svc.cluster.local for direct peer communication.

DNS Stability Across Rescheduling

When a StatefulSet Pod is rescheduled to a different node, it gets a new IP address. However, the DNS record is updated to point to the new IP, so the hostname mysql-0.mysql-headless remains valid. This is the key benefit — applications reference Pods by DNS name, not IP, and the name never changes.

Why Interviewers Ask This

Interviewers ask this to test whether you understand the networking model behind StatefulSets and how individual Pods are discovered by peer applications in a cluster.

Common Follow-Up Questions

What DNS records does a Headless Service create for a StatefulSet?
It creates an A record for each Pod mapping <pod-name>.<service-name> to the Pod's IP, plus an SRV record for the service that lists all Pods.
Can you use a regular ClusterIP Service with a StatefulSet?
You can create one for client traffic, but the StatefulSet spec requires a Headless Service for the serviceName field to provide Pod-level DNS.
What happens if the Headless Service is deleted?
The DNS records for individual Pods are removed, breaking peer discovery. The Pods themselves continue running but cannot be addressed by name.

Key Takeaways

  • The Headless Service provides DNS-based identity, not load balancing — each Pod gets its own DNS record.
  • The StatefulSet's serviceName field must reference a Headless Service for Pod DNS to work.
  • You can create an additional regular Service for load-balanced client access alongside the Headless Service.

Related Questions

You Might Also Like