StatefulSet
Applicativi stateful gestiscono dati e hanno bisogno di tracciarli continuamente, per esempio MySQL, Oracle e PostgreSQL.
Uno StatefulSet è il controller appropriato per un applicativo stateful.
Ad ogni pod gestito viene assegnato un numero identificativo ordinale anzichè casuale e i pod vengono creati in ordine e cancellati in ordine inverso. Un nuovo pod è creato clonando il pod precedente solo quando è nello stato Running.
Le richieste di lettura da un volume associato vengono inviate a tutti i pod dello StatefulSet. Le richieste di scrittura sul volume associato vengono inviate solo al primo pod, e i dati modificati sono sincronizzati agli altri pod.
Cancellare un pod di uno StatefulSet non rimuove i volumi associati con l'applicativo.
Per l'esercizio che segue occorrono due Persistent Volumes, che i pod dello Stateful Set useranno. Normalmente un Provisioner creerebbe volumi dinamici all'occorrenza.
Il manifest che segue combina la definizione dei due persistent volumes con quella dello StatefulSet:
vim ~/scripts/stateful.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: www-volume-1
spec:
storageClassName: standard
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/www/
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: www-volume-2
spec:
storageClassName: standard
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data/www/
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.k8s.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
Aprire due finestre di terminale.
Nella prima digitare:
kubectl get pods --watch -l app=nginx
Nella seconda digitare:
kubectl apply -f ~/scripts/stateful.yml
Mentre nella seconda viene generato l'applicativo, il rapporto nella prima finestra è:
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 1s
web-0 0/1 ContainerCreating 0 1s
web-0 1/1 Running 0 5s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 2s
web-1 0/1 ContainerCreating 0 3s
web-1 1/1 Running 0 9s
I pod sono generati in sequenza.
Il pod web-1
viene generato solo quando il pod web-0
è nello stato di Running.
Il servizio è dato da:
kubectl get service nginx
Lo StatefulSet è dato da:
kubectl get statefulset web
I pod dell'applicativo si possono vedere con:
kubectl get pods -l app=nginx
Ogni pod ha uno hostname basato sul suo numero ordinale. Si possono vedere con:
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
Il loro nome è risolto al DNS di cluster. Si può compire un'interrogazione lanciando un pod aggiuntivo nel cluster:
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
E al pronto risultante dare:
nslookup web-0.nginx
Proviamo a cancellare esplicitamente i pod dello StatefulSet.
In una finestra digitare:
kubectl get pod --watch -l app=nginx
E nell'altra finestra digitare:
kubectl delete pod -l app=nginx
I pod vengono cancellati, ma subito ricreati, in ordine.
Scalare uno StatefulSet
In una finestra dare:
kubectl get pods --watch -l app=nginx
E nell'altra finestra:
kubectl scale sts web --replicas=5
Si nota che la creazione di nuovi pod procede per gradi, il nuovo pod sequenziale non viene creato finchè il precedente non è nello ststo di Running.
Si può anche scalare a decrescere, applicando una patch:
kubectl patch sts web -p '{"spec":{"replicas":3}}'
E' da notare che i Persistent Volume Claims sono ancora 5:
kubectl get pvc -l app=nginx
I PVC creati da uno StatefulSet non vengono cancellati anche quando sono cancellati i pod che li usano.
E' da notare che durante l'operazione di scale sono stati costruiti tre ulteriori Persistent Volumes, ma con una policy di Delete, anzichè Retain.
Cancellazione di uno StatefulSet
Tramite il manifest:
kubectl delete -f ~/scripts/stateful.yml
I PVC e i loro PV non vengono cancellati. I PV creati da manifest entrano in stato Terminating ma non sono rimossi finchè i corrispondenti PVC non vengono cancellati.
Cancellare a mano i PVC:
kubectl delete pvc www-web-0 www-web-1 www-web-2 www-web-3 www-web-4
I rimanenti PV sono temporaneamente visibili, ma vengono presto cancellati.