K8S-Data: StatefulSets
Intro
In Kubernetes, a StatefulSet is a workload API object designed for stateful applications that require stable, unique network identities and persistent storage. Unlike Deployments, StatefulSets ensure ordered deployment, scaling, and deletion of Pods, making them ideal for databases and distributed systems.
Key Features of StatefulSet:
Stable Pod Identity – Each Pod gets a predictable hostname (
pod-0,pod-1, etc.).Ordered Deployment & Scaling – Ensures Pods are created or deleted in a specific sequence.
Persistent Storage – Each Pod gets a dedicated PVC that remains even if the Pod is rescheduled.
Common Use Cases:
Databases (MySQL, PostgreSQL, MongoDB)
Distributed systems (Elasticsearch, Kafka, Zookeeper)
Applications needing stable network identities
By leveraging StatefulSets, Kubernetes enables reliable stateful application management with built-in data persistence and predictable behavior.
Headless Service
A Headless Service in Kubernetes is a special type of service (clusterIP: None) that allows direct pod-to-pod communication without load balancing. Unlike a normal service, it doesn’t assign a single virtual IP but instead provides DNS-based discovery of individual pod IPs.
Key Features of Headless Services:
No ClusterIP → Allows direct access to pod IPs.
DNS-Based Pod Discovery → Resolves to multiple pod endpoints instead of a single load-balanced IP.
Essential for Stateful Workloads → Used with StatefulSets for applications requiring stable network identities (e.g., databases, distributed systems).
Use Cases:
Databases (MySQL, Cassandra, Elasticsearch) → Nodes need stable hostnames.
Peer-to-Peer Applications → Pods communicate directly without load balancing.
Service Discovery for Microservices → Enable dynamic pod discovery.
By using a Headless Service, Kubernetes provides flexible networking for stateful and distributed applications, ensuring stability and scalability.
Demo
This demo will show how to deploy Nginx using StatefulSet, demonstrating stable pod names, ordered scaling, and persistent storage.
Create a Headless Service
StatefulSets require a headless service to provide stable network identities.
apiVersion: v1
kind: Service
metadata:
name: nginx-sts-svc
spec:
clusterIP: None # Headless service
selector:
app: nginx
ports:
- name: http
port: 80
Create a StatefulSet
This StatefulSet ensures Pods get predictable hostnames and each one gets its own persistent storage.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-sts
spec:
serviceName: "nginx-sts-svc" # Connects with the headless service
replicas: 3 # Deploy 3 Nginx pods
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx-k8s:latest
imagePullPolicy: Never
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /usr/share/nginx/html # Store HTML files persistently
volumeClaimTemplates:
- metadata:
name: nginx-storage
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi # Each pod gets its own 1Gi volume
Verify StatefulSet Behavior
Check Pod Names
$ kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-sts-0 1/1 Running 0 35s app=nginx,apps.kubernetes.io/pod-index=0,controller-revision-hash=nginx-sts-686576c7b8,statefulset.kubernetes.io/pod-name=nginx-sts-0
nginx-sts-1 1/1 Running 0 35s app=nginx,apps.kubernetes.io/pod-index=1,controller-revision-hash=nginx-sts-686576c7b8,statefulset.kubernetes.io/pod-name=nginx-sts-1
nginx-sts-2 1/1 Running 0 30s app=nginx,apps.kubernetes.io/pod-index=2,controller-revision-hash=nginx-sts-686576c7b8,statefulset.kubernetes.io/pod-name=nginx-sts-2
Each pod gets a stable, predictable name.
Check PV and PVC
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-94beef87-0eab-411e-b933-4250f2d5e613 1Gi RWO Delete Bound default/nginx-storage-nginx-sts-0 standard <unset> 6m43s
pvc-d223f22a-161e-47fe-8fa4-5c6881d87d3d 1Gi RWO Delete Bound default/nginx-storage-nginx-sts-1 standard <unset> 4m12s
pvc-f142e982-e61d-4f82-9577-cefd7d2de80f 1Gi RWO Delete Bound default/nginx-storage-nginx-sts-2 standard <unset> 4m7s
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
nginx-storage-nginx-sts-0 Bound pvc-94beef87-0eab-411e-b933-4250f2d5e613 1Gi RWO standard <unset> 3m47s
nginx-storage-nginx-sts-1 Bound pvc-d223f22a-161e-47fe-8fa4-5c6881d87d3d 1Gi RWO standard <unset> 77s
nginx-storage-nginx-sts-2 Bound pvc-f142e982-e61d-4f82-9577-cefd7d2de80f 1Gi RWO standard <unset> 72s
Each Pod will have a dedicated PVC.
Test Networking Between Pods
Inside the number 0 container, test the connection to another pod:
root@nginx-sts-0:/# curl nginx-sts-1.nginx-sts-svc.default.svc.cluster.local
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.4</center>
</body>
</html>
This shows that each pod can communicate via a stable DNS name.

