Let's define a simple StatefulSet to deploy nginx "hello-nginx-statefulset":
$ vi hello-nginx-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx # must be a valid DNS name. it will be used to create the name of the Pods: nginx-0, nginx-1, ...
spec:
selector:
matchLabels:
app: nginx # needs to match spec.template.metadata.labels
serviceName: "nginx" # needs to match the name of the headless Service
replicas: 2 # by default is 1. Will create two pods: nginx-0, nginx-1
template:
metadata:
labels:
app: nginx # needs to match spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:latest
ports:
- name: nginx
containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www # will be used to name the PVCs of the pods: www-nginx-0, www-nginx-1, ...
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class-name" # needs to match the storage class name
resources:
requests:
storage: 1Gi
If you are using Kubernetes on Docker Desktop, you will need to adjust the volumeClaimTemplates section as following:
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "hostpath" # needs to match the storage class name
resources:
requests:
storage: 1Gi
selector:
matchLabels:
type: local
If you are using Kubernetes on Docker Desktop, you also need to define a Persistent Volume (hostPath) for each Pod replica.
For more details, see
Volumes.
$ vi hello-nginx-statefulset-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: www-nginx-0
labels:
type: local
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: hostpath
capacity:
storage: 1Gi
hostPath:
path: "/mnt/mydata/nginx-pv-data"
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: www-nginx-1
labels:
type: local
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: hostpath
capacity:
storage: 1Gi
hostPath:
path: "/mnt/mydata/nginx-pv-data"
Let's define the headless Service:
$ vi hello-nginx-headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- name: nginx
port: 80
clusterIP: None # indicates a headless Service
selector:
app: nginx
Let's create the Persistent Volumes (again this is needed only for Kubernetes on Docker Desktop):
$ kubectl apply -f hello-nginx-statefulset-pv.yaml
persistentvolume/www-nginx-0 created
persistentvolume/www-nginx-1 created
View the Persistent Volumes (the STATUS is Available):
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
www-nginx-0 1Gi RWO Retain Available hostpath 17s
www-nginx-1 10Gi RWO Retain Available hostpath 17s
Let's create the StatefulSet:
$ kubectl apply -f hello-nginx-statefulset.yaml
statefulset.apps/nginx created
Check the Pods creation:
$ kubectl get pods --watch
NAME READY STATUS RESTARTS AGE
nginx-0 0/1 ContainerCreating 0 2s
nginx-0 1/1 Running 0 19s
nginx-1 0/1 Pending 0 0s
nginx-1 0/1 Pending 0 0s
nginx-1 0/1 Pending 0 3s
nginx-1 0/1 ContainerCreating 0 3s
nginx-1 1/1 Running 0 5s
Check the Persistent Volume Claims:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-nginx-0 Bound www-nginx-0 1Gi RWO hostpath 79s
www-nginx-1 Bound www-nginx-1 10Gi RWO hostpath 60s
Check again the Persistent Volumes (the STATUS should be Bound now):
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
www-nginx-0 1Gi RWO Retain Bound default/www-nginx-0 hostpath 4m5s
www-nginx-1 10Gi RWO Retain Bound default/www-nginx-1 hostpath 4m5s
Let's create the headless Service:
$ kubectl apply -f hello-nginx-headless-service.yaml
service/nginx created
Check the headless Service:
$ kubectl get service nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 5m6s