In this guide, we’ll walk through deploying a Kubernetes StatefulSet, attaching persistent volumes, and exposing it via a headless service in Google Kubernetes Engine (GKE).
We’ll also explore what happens when StatefulSet Pods are deleted — and how Kubernetes ensures state persistence.
🧠 Step 01: Introduction
In this demo, you will:
✅ Create and deploy a StatefulSet
✅ Create a Headless Service to access StatefulSet pods
✅ Verify pod identity, storage persistence, and behavior during pod recreation
🧩 Step 02: Review 01-kubernetes-statefulset.yaml
Each StatefulSet Pod will get its own PersistentVolumeClaim (PVC).
Here, we use the premium-rwo storage class in GKE.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myapp1-sts
spec:
selector:
matchLabels:
app: nginx
serviceName: "myapp1-hs-svc"
replicas: 3
minReadySeconds: 10
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
initContainers:
- name: init-pass-hostname
image: alpine
command: ["/bin/sh", "-c", "echo POD_HOSTNAME: $HOSTNAME > /usr/share/nginx/html/index.html"]
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
containers:
- name: nginx
image: ghcr.io/stacksimplify/kubenginx:1.0.0
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "premium-rwo"
resources:
requests:
storage: 1Gi
📝 Key Points:
- Each Pod gets its own unique PVC using volumeClaimTemplates
- Pods are created one by one, not simultaneously
- The init container writes its hostname to /usr/share/nginx/html/index.html
🧠 Step 03: Review 02-kubernetes-headless-service.yaml
A Headless Service gives each StatefulSet Pod a unique DNS entry instead of load balancing them.
apiVersion: v1
kind: Service
metadata:
name: myapp1-hs-svc
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
📝 Key Points:
- clusterIP: None makes it headless
- Each Pod gets its own resolvable DNS name
Example:
- myapp1-sts-0.myapp1-hs-svc.default.svc.cluster.local
- myapp1-sts-1.myapp1-hs-svc.default.svc.cluster.local
🧠 Step 04: Review 03-curl-pod.yaml
We’ll use this simple pod to test the headless service connectivity.
apiVersion: v1
kind: Pod
metadata:
name: curl-pod
spec:
containers:
- name: curl
image: curlimages/curl
command: [ "sleep", "600" ]
⚙️ Step 05: Deploy StatefulSet and Verify
# Deploy Kubernetes manifests
kubectl apply -f kube-manifests/01-kubernetes-statefulset.yaml
kubectl apply -f kube-manifests/02-kubernetes-headless-service.yaml
kubectl apply -f kube-manifests/03-curl-pod.yaml
# List Pods
kubectl get pods
🧩 Observations:
- Pods are created one after another.
- Each Pod gets its own PVC automatically.
kubectl get statefulset
kubectl describe sts myapp1-sts
✅ You’ll see:
- PVC created for Pod-0, then Pod-0 starts
- PVC created for Pod-1, then Pod-1 starts
- PVC created for Pod-2, then Pod-2 starts
🗄️ Step 06: Verify Persistent Volumes
kubectl get pvc
kubectl get pv
Then, go to Google Cloud Console → Compute Engine → Disks
🧩 Observation:
You’ll see 3 Persistent Disks automatically created — one for each StatefulSet pod.
🌐 Step 07: Verify Headless Service
kubectl get svc
kubectl describe svc myapp1-hs-svc
kubectl get endpoints myapp1-hs-svc
🧩 Observation:
Endpoints look like:
10.124.0.11:80, 10.124.1.12:80, 10.124.2.11:80
Test using curl-pod
kubectl exec -it curl-pod -- /bin/sh
Inside curl-pod, run:
curl myapp1-hs-svc.default.svc.cluster.local
Or continuously:
while true; do curl -s "http://myapp1-hs-svc.default.svc.cluster.local"; sleep 1; done
🧩 Observation:
You’ll see responses from multiple Pods, confirming traffic distribution.
Test individual Pod endpoints
# nslookup test
nslookup myapp1-sts-0.myapp1-hs-svc.default.svc.cluster.local
nslookup myapp1-sts-1.myapp1-hs-svc.default.svc.cluster.local
nslookup myapp1-sts-2.myapp1-hs-svc.default.svc.cluster.local
# curl test
curl myapp1-sts-0.myapp1-hs-svc.default.svc.cluster.local
curl myapp1-sts-1.myapp1-hs-svc.default.svc.cluster.local
curl myapp1-sts-2.myapp1-hs-svc.default.svc.cluster.local
🧩 Observation:
- Each request goes directly to the specific Pod. (Perfect for databases like MySQL master/replica setups.)
🔁 Step 08: Delete a Pod and Observe Behavior
kubectl get pods
kubectl delete pod myapp1-sts-0
kubectl get pods
🧩 Observation:
The Pod is automatically recreated with the same name (myapp1-sts-0)
It reattaches the same PersistentVolumeClaim
Verify:
kubectl describe pod myapp1-sts-0
✅ You’ll see the same claim name:
ClaimName: www-myapp1-sts-0
🧹 Step 09: Clean-Up
# Delete manifests
kubectl delete -f kube-manifests/01-kubernetes-statefulset.yaml
kubectl delete -f kube-manifests/02-kubernetes-headless-service.yaml
kubectl delete -f kube-manifests/03-curl-pod.yaml
🧩 Observation:
PVCs and PVs still remain — Persistent data survives even after StatefulSet deletion.
To fully clean up:
kubectl delete pvc www-myapp1-sts-0
kubectl delete pvc www-myapp1-sts-1
kubectl delete pvc www-myapp1-sts-2
Then confirm:
kubectl get pvc
kubectl get pv
🧩 Observation:
- Volumes will take a couple of minutes to delete.
- Check in GCP → Compute Engine → Disks to verify deletion.
✅ Summary
Concept | Description |
---|---|
StatefulSet | Manages Pods with stable identity and storage |
Headless Service | Provides DNS-based access to individual Pods |
PVC/PV | Ensures persistent data even if Pods restart |
Deletion Behavior | Pods recreate with the same name and storage |
💡 Real-World Use Cases
- Databases (MySQL, PostgreSQL)
- Message Brokers (Kafka, RabbitMQ)
- Caching Systems (Redis)
- Search Engines (Elasticsearch)
- Coordination Services (Zookeeper, Cassandra)
🎯 Final Thoughts
StatefulSets are essential when your workloads require stable identity, ordered deployment, and persistent storage.
They ensure data integrity and reliable scaling for stateful workloads — a cornerstone of modern cloud-native database and messaging systems.
🌟 Thanks for reading! If this post added value, a like ❤️, follow, or share would encourage me to keep creating more content.
— Latchu | Senior DevOps & Cloud Engineer
☁️ AWS | GCP | ☸️ Kubernetes | 🔐 Security | ⚡ Automation
📌 Sharing hands-on guides, best practices & real-world cloud solutions
Top comments (0)