Lab 6.4 - StatefulSet with Persistent Storage
Lab Objectives
By the end of this lab, you will be able to:
- Create a StatefulSet with persistent volumes.
- Understand volume provisioning for each Pod.
- Verify stable Pod and volume identities.
- Test data persistence during restarts.
- Understand the differences between StatefulSet and Deployment for storage.
Estimated Duration
60-75 minutes
Prerequisites
- kubectl installed and configured.
- Functional local Kubernetes cluster (minikube or kind).
- Knowledge of StatefulSets and persistent storage (Chapters 6.4 and 7.1).
Part 1: StorageClass Preparation
For a StatefulSet, each Pod needs its own persistent volume. We will use a StorageClass for dynamic provisioning.
Step 1.1: Create a StorageClass
Create a file storageclass-statefulset.yaml:
# storageclass-statefulset.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: statefulset-storage
provisioner: k8s.io/minikube-hostpath # For minikube, or kubernetes.io/no-provisioner for kind
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
allowVolumeExpansion: false
Note: If using kind or a cluster without a provisioner, you will need to create PVs manually. For this lab, we assume minikube.
Apply the StorageClass:
kubectl apply -f storageclass-statefulset.yaml
Part 2: Creating a StatefulSet with Storage
We will create a simple StatefulSet that stores data in persistent volumes.
Step 2.1: Create the StatefulSet
Create a file statefulset-with-storage.yaml:
# statefulset-with-storage.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-app
spec:
serviceName: web-app-service # Headless Service name (required for StatefulSet)
replicas: 3 # Create 3 Pods
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html # Persistent volume mount
command: ["/bin/sh", "-c"]
args:
- |
echo "Pod $(hostname) - $(date)" > /usr/share/nginx/html/index.html
echo "Persistent data from Pod $(hostname)" >> /usr/share/nginx/html/data.txt
nginx -g "daemon off;"
volumeClaimTemplates: # Template to create a PVC for each Pod
- metadata:
name: www # Volume name (used in volumeMounts)
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: statefulset-storage # Uses our StorageClass
resources:
requests:
storage: 100Mi # Volume size for each Pod
Explanation:
serviceName: web-app-service: A StatefulSet requires a headless Service for DNS discovery.volumeClaimTemplates: Automatically creates a PVC for each Pod in the StatefulSet. Each Pod will have its own persistent volume.- Pods will be named
web-app-0,web-app-1,web-app-2in order.
Step 2.2: Create the Headless Service
A StatefulSet requires a headless Service (ClusterIP with clusterIP: None) for DNS discovery:
# service-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: web-app-service
spec:
clusterIP: None # Headless service
selector:
app: web-app
ports:
- port: 80
name: web
Apply the Service:
kubectl apply -f service-headless.yaml
Apply the StatefulSet:
kubectl apply -f statefulset-with-storage.yaml
Part 3: Observing Provisioning
Step 3.1: Verify Pod Creation
StatefulSet Pods are created sequentially (one by one):
kubectl get pods -l app=web-app -w
You should see Pods created in order: web-app-0, then web-app-1, then web-app-2.
Step 3.2: Verify Created PVCs
Each Pod has its own PVC:
kubectl get pvc
You should see three PVCs:
www-web-app-0www-web-app-1www-web-app-2
Each PVC is bound to its own PV:
kubectl get pv
Step 3.3: Verify Data in Each Pod
Each Pod has its own persistent data:
# Pod 0
kubectl exec web-app-0 -- cat /usr/share/nginx/html/index.html
kubectl exec web-app-0 -- cat /usr/share/nginx/html/data.txt
# Pod 1
kubectl exec web-app-1 -- cat /usr/share/nginx/html/index.html
kubectl exec web-app-1 -- cat /usr/share/nginx/html/data.txt
# Pod 2
kubectl exec web-app-2 -- cat /usr/share/nginx/html/index.html
kubectl exec web-app-2 -- cat /usr/share/nginx/html/data.txt
Each Pod should display its own hostname and data.
Part 4: Persistence Test
Step 4.1: Add Unique Data
Add unique data to each Pod:
kubectl exec web-app-0 -- sh -c "echo 'Unique data Pod 0 - $(date)' >> /usr/share/nginx/html/data.txt"
kubectl exec web-app-1 -- sh -c "echo 'Unique data Pod 1 - $(date)' >> /usr/share/nginx/html/data.txt"
kubectl exec web-app-2 -- sh -c "echo 'Unique data Pod 2 - $(date)' >> /usr/share/nginx/html/data.txt"
Verify the data:
kubectl exec web-app-0 -- cat /usr/share/nginx/html/data.txt
Step 4.2: Delete a Pod
Delete a Pod to test persistence:
kubectl delete pod web-app-0
The StatefulSet will automatically recreate the Pod with the same name (web-app-0).
Wait for the new Pod to be Running:
kubectl get pods -l app=web-app
Step 4.3: Verify Persistence
Verify that data is still present after the restart:
kubectl exec web-app-0 -- cat /usr/share/nginx/html/data.txt
You should see all previous data, including "Unique data Pod 0", proving that the persistent volume was remounted with the same data.
Part 5: StatefulSet Scaling
Step 5.1: Increase Replica Count
Increase the number of Pods:
kubectl scale statefulset web-app --replicas=5
Verify that new Pods and PVCs are created:
kubectl get pods -l app=web-app
kubectl get pvc
You should see web-app-3 and web-app-4 with their respective PVCs.
Step 5.2: Decrease Replica Count
Reduce the number of Pods:
kubectl scale statefulset web-app --replicas=2
Verify that Pods are deleted in reverse order (from highest to lowest):
kubectl get pods -l app=web-app -w
Important: PVCs are NOT automatically deleted. Verify:
kubectl get pvc
The PVCs from deleted Pods (www-web-app-2, www-web-app-3, www-web-app-4) are still present, preserving the data.
Part 6: Cleanup
Delete the created resources:
kubectl delete statefulset web-app
kubectl delete service web-app-service
kubectl delete pvc -l app=web-app # Delete all StatefulSet PVCs
# PVs will be automatically deleted if reclaimPolicy: Delete
kubectl delete -f storageclass-statefulset.yaml
Lab Summary
In this lab, you explored using StatefulSets with persistent storage. You learned to create a StatefulSet with volumeClaimTemplates, observe sequential Pod and volume provisioning, test data persistence during restarts, and understand scaling behavior with persistent volumes.
Next Steps
This storage module is now complete. You can proceed to Module 7 on Advanced Workloads.
Module 7: Advanced Workloads
Lab created: December 2024