The Problem with Traditional Services
Under typical conditions, Kubernetes services function as load balancers. They provide a Cluster IP and a DNS name (like mysql.default.svc.cluster.local) that routes traffic evenly to all matching pods. This behavior is acceptable when the application only performs read operations in a MySQL cluster but becomes problematic for write operations. Write queries must be directed solely to the master pod, and load balancing across all pods could lead to data inconsistency or conflicts.How Headless Services Address the Issue
Headless services eliminate the load balancing behavior by not assigning a Cluster IP. Instead, they generate DNS records for each individual pod in the following format: pod-name.headless-service-name.namespace.svc.cluster.local For example, if you create a headless service named “mysql-h”, the master pod can be accessed via: mysql-0.mysql-h.default.svc.cluster.local This DNS entry consistently resolves to the master pod in the MySQL deployment.In a headless service, setting
clusterIP to “None” is the only key difference from a standard service definition.Headless Service Definition Example
Below is an example of how to define a headless service:Configuring Pods to Use Headless Services
When deploying a pod under a headless service, include the optional fieldssubdomain and hostname in the pod specification. The subdomain must match the name of your headless service, ensuring that Kubernetes creates the correct DNS record.
For example, to create a pod with only the subdomain specified:
hostname field as well:
Visual Overview of a MySQL Cluster Setup
The diagram below illustrates the setup of a MySQL database cluster with one master and two replicas. It highlights the network configuration, including IP addresses and hostnames:
Deployments vs. StatefulSets
When deploying pods using a Deployment, the pod template generally does not specify thehostname or subdomain fields. Consequently, the headless service is unable to create unique A records for each pod. If these fields are manually added to the pod template, every pod receives the same DNS record, resulting in an address like mysql-pod.mysql-h.default.svc.cluster.local, which is unsuitable for distinct addressing.
Deployment Example with Identical DNS Records
Below is an example where a Deployment assigns the same hostname and subdomain to all pods:Leveraging StatefulSets for Unique DNS Records
StatefulSets are designed to overcome this limitation by automatically generating unique hostnames for each pod. You do this by simply referencing the headless service name in the StatefulSet specification using theserviceName field. Kubernetes then assigns a unique DNS record to each pod based on its ordinal index.
StatefulSet Example with Headless Service
Below is an example of a StatefulSet that utilizes a headless service:mysql-1.mysql-h.default.svc.cluster.local
mysql-2.mysql-h.default.svc.cluster.local This setup meets the requirement for distinct addressing, ensuring that write requests intended for the master pod are routed correctly.
StatefulSets combined with headless services provide a robust solution for applications requiring individual pod addressing without load balancing interference.