StatefulSets (Pods with Persistent Volumes)
Introduction
Like a Deployment, a StatefulSet manages Pods that are based on an identical container spec. Unlike a Deployment, a StatefulSet maintains 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 (UID) that it maintains across any rescheduling. It also provides guarantees on the ordering and uniqueness of the Pods.
StatefulSets also require a headless service to manage network identities for pods. Each Pod gets a sticky network subdomain and SRV record that does not change if a Pod is deleted and recreated.
You can see an example below where a Pod is deleted, but then recreated with the same name
using the StatefulSet spec.
kubectl get pods
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3d
web-1 1/1 Running 0 3d
kubectl delete pod web-0
pod "web-0" deleted
kubectl get pods
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 7s
web-1 1/1 Running 0 3d
Headless Service
As mentioned above, a headless service is required for StatefulSets, where the network type clusterIP
has a value of None
. This does not predefine an IP for the service.
apiVersion: v1
kind: Service
metadata:
name: nginx-service #Name of Service
labels:
app: nginx # Pod label
spec:
ports:
- port: 8080 # Mapped port used by service
name: web # Named port
clusterIP: None # Headless service setting
selector:
app: nginx # Selector should match the name of the app being deployed as the Statefulset
StatefulSet creation
Below is an example of a StatefulSet definition:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web # Name of StatefulSet
spec:
selector:
matchLabels:
app: nginx # defines a set of pods to be managed by the StatefulSet
serviceName: "nginx-service" # The name of the headless service
replicas: 3
template:
metadata:
labels:
app: nginx # This should be the same of selector:matchLabels:app
spec:
containers: # Container images with their corresponding settings
- name: nginx
image: bitnami/nginx:latest
ports:
- containerPort: 8080
name: web
volumeMounts:
- name: www
mountPath: "/usr/share/nginx/html"
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "gp2-expand" # StorageClass name used to create PV
resources:
requests:
storage: 4Gi # Storage resource request size
Please use StorageClass gp2-expand
to be able to expand PersistentVolumes in the future.
Once all pods are created for the StatefulSet, they have a unique identity based on the metadata name of the StatefulSet. The pods are named using the following: [StatefulSet_Name]-[Ordinal_Index] e.g. web-0
kubectl get pods
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 22m
web-1 1/1 Running 0 22m
web-2 1/1 Running 0 21m
web-3 1/1 Running 0 21m
web-4 1/1 Running 0 20m
web-5 1/1 Running 0 20m
web-6 1/1 Running 0 20m
All PersistentVolumeClaims would have all been created also. The PersistentVolumeClaims are named using the following: [VolumeClaim_Name]-[StatefulSet_Name]-[Ordinal_Index]
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-0ca662d1-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 29m
www-web-1 Bound pvc-1cc800d2-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 28m
www-web-2 Bound pvc-2abbbeb6-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 28m
www-web-3 Bound pvc-40e2bc95-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 27m
www-web-4 Bound pvc-4ebb8afd-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 27m
www-web-5 Bound pvc-641f5a61-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 26m
www-web-6 Bound pvc-6c2a187c-9299-11e9-b4c5-0a5b8815a91e 4Gi RWO gp2-expand 26m
If a Pod is deleted, it will be rescheduled, with the same name, and the corresponding above PersistentVolumeClaims will be attached. The Pod also has and will keep a network ID that persists through restarts.
If a StatefulSet is deleted, the PersistentVolumeClaims (PVCs) remain along with PersistentVolumes (PVs). PVCs and PVs have to be deleted separately.
Advisory note: Expanding Persistent Volumes
It is currently not possible to expand PVs using the StatefulSet template. There is a manual way to do this, which the Cloud Platform team can help with if required.