Kubernetes StatefulSet Practical: Hands-On Tutorial with Nginx & Persistent Storage

Practical Kubernetes StatefulSet tutorial with step-by-step examples, YAML configuration, kubectl commands, persistent volumes, headless services, and data persistence demonstrations.

StatefulSet Example

Download the YAML configuration file for the StatefulSet example

Download statefulset.yaml

Create the StatefulSet

kubectl apply -f statefulset.yaml

Applies the configuration from the YAML file to create the StatefulSet with 3 replicas.

Get the Pods List

kubectl get pods -o wide

Shows all pods with additional details like IP addresses and node assignments.

Get PersistentVolume Claims

kubectl get pvc

Lists all PersistentVolume Claims created by the StatefulSet.

Create a File in nginx-sts-2

kubectl exec nginx-sts-2 -it -- /bin/sh
cd /var/www
echo Hello > hello.txt

Opens a shell in the nginx-sts-2 pod and creates a file in the mounted volume.

Modify the Default Web Page

cd /usr/share/nginx/html
cat > index.html
Hello
Ctrl-D
exit

Changes the default Nginx web page content.

Reach nginx-sts-2 from nginx-sts-0

kubectl exec nginx-sts-0 -it -- /bin/sh
curl http://nginx-sts-2.nginx-headless
exit

Tests connectivity between pods using the headless service DNS.

Delete Pod 2

kubectl delete pod nginx-sts-2

Deletes the pod and watches as it is recreated with the same name.

Check if the File Still Exists

kubectl exec nginx-sts-2 -it -- /bin/sh
ls /var/www
exit

Verifies that the file persists after pod recreation due to PersistentVolume.

Cleanup - Delete StatefulSet

kubectl delete -f statefulset.yaml

Deletes the StatefulSet and its pods.

Cleanup - Delete PVCs

kubectl delete pvc www-nginx-sts-0
kubectl delete pvc www-nginx-sts-1
kubectl delete pvc www-nginx-sts-2

Deletes the PersistentVolume Claims to clean up storage resources.

YAML Configuration File

apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
  labels:
    run: nginx-sts-demo
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    run: nginx-sts-demo
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-sts
spec:
  serviceName: nginx-headless
  replicas: 3
  selector:
    matchLabels:
      run: nginx-sts-demo
  template:
    metadata:
      labels:
        run: nginx-sts-demo
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: www
          mountPath: /var/www/
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      storageClassName: hostpath
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 10Mi

YAML Configuration Explanation:

Headless Service:

  • apiVersion: v1 → Specifies the Kubernetes API version
  • kind: Service → Defines this as a Service resource
  • metadata.name: nginx-headless → Names the service
  • clusterIP: None → Makes this a headless service (no load balancing)
  • selector.run: nginx-sts-demo → Selects pods with this label

StatefulSet Configuration:

  • apiVersion: apps/v1 → StatefulSet API version
  • kind: StatefulSet → Defines this as a StatefulSet resource
  • metadata.name: nginx-sts → Names the StatefulSet
  • serviceName: nginx-headless → Associates with the headless service
  • replicas: 3 → Creates 3 pod replicas
  • selector.matchLabels.run: nginx-sts-demo → Selects pods with this label

Pod Template:

  • template.metadata.labels.run: nginx-sts-demo → Labels for the pods
  • spec.containers.name: nginx → Container name
  • spec.containers.image: nginx → Uses the official Nginx image
  • volumeMounts.name: www → Mounts the volume named "www"
  • volumeMounts.mountPath: /var/www/ → Mounts to this directory in the container

Volume Claim Template:

  • volumeClaimTemplates.metadata.name: www → Names the volume claim template
  • storageClassName: hostpath → Uses hostPath storage class
  • accessModes: ReadWriteOnce → Volume can be mounted as read-write by a single node
  • resources.requests.storage: 10Mi → Requests 10MB of storage

How StatefulSets Work:

StatefulSets maintain a sticky identity for each of their Pods. These pods are created from the same spec, but are not interchangeable: each has a persistent identifier that it maintains across any rescheduling. When a StatefulSet's Pod is deleted, it is recreated with the same name and network identity. Each pod in a StatefulSet gets its own PersistentVolumeClaim, ensuring data persistence even when pods are rescheduled.