Storaggio

Kubernetes supporta numerosi tipi di storaggio: iSCSI, SMB, NFS, object storage blobs, ecc. I fornitori (Provisioner) di storaggio possono essere in-house o nel cloud.

E' necessario che Kubernetes installi un plugin per supportare lo storaggio specifico, fornito dal Provisioner.

Il plugin deve essere conforme allo standard CSI - Container Storage Interface.

Csiplugin

Purtroppo i cluster Kind e Minikube non supportano questa funzionalità e sono limitati allo storaggio Standard - locale, o NFS visto come directory locale.

Per esempio un cluster è implementato su AWS e l'amministratore di AWS ha creato un volume di 25GB chiamato ebs-vol. L'amministratore di Kubernetes crea un PV chiamato k8s-vol collegato al volume ebs-vol dal plugin kubernetes.io/aws-ebs.

Ebsplugin

Sistema Persistent Volume

Le tre risorse principlali del sistema Persistent Volume sono:

  • Persistent Volume (pv)
  • Persistent Volume Claim (pvc)
  • Storage Class (sc)

I passi in Kubernetes sono:

  1. Creare il PV
  2. Creare il PVC
  3. Definire il volume nelle specifiche di un Pod
  4. Montarlo in un container

Esempio di creazione di PV.

vim gke-volume.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: test
  capacity:
    storage: 10Gi
  persistentVolumeReclaimPolicy: Retain
  gcePersistentDisk:
    pdName: user-disk

Il PV è altamente specifico al Provisioner. Per esempio l'attributo gcePersistentDisk si riferisce a Gookle e ha bisogno della presenza del plugin GCE. Il volume user-disk deve essere stato creato prima da GCE.

Anche la storage class di nome test è creata altrove.

Questo è solo un esempio illustrativo, non funziona col nostro cluster.

L'effetto graficamente espresso sarebbe:

Userdisk

La proprietò .spec.persistentVolumeReclaimPolicy dice a Kubernetes cosa farne del disco PV quando non è più in uso. Due possibilità:

  • Delete
  • Retain

Retain ne conserva i dati, ma non sono più accessibili da un altro PVC in futuro. Il PV deve essere rimosso a mano.

Un PVC corrispondente a questo PV sarebbe ad esempio:

vim gke-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: test
  resources:
    requests:
      storage: 10Gi

Vi sono alcune proprietà che devono essere in corrispondenza:

Corrispond

Un pod che usa questo PVC potrebbe essere:

vim volpod.yml
apiVersion: v1
kind: Pod
metadata:
  name: volpod
spec:
volumes:
  - name: data
    persistentVolumeClaim:
      claimName: pvc1
containers:
  - name: ubuntu-ctr
    image: ubuntu:latest
    command:
    - /bin/bash
    - "-c"
    - "sleep 60m"
    volumeMounts:
    - mountPath: /data
      name: data

Dynamic Provisioning

Il Dynamic Provisioning è la fornitura da parte del Provider di spazio disco on-demand, quando c'è un Pod che effettivamente lo usa.

Questa funzionalità è basata sul concetto di Storage Class.

Storage Class

Una StorageClass è una risorsa definita nel gruppo API storage.k8s.io/v1. Si riferisce ad un tipo di storaggio offerto da un Provisioner.

Esempio.

vim fast-sc.yml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  zones: eu-west-1a
  opsPerGB: "10"

Sottomettere il manifest:

kubectl apply -f fast-sc.yml

Si visionano le storage classes con:

kubectl get sc
NAME                 PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
fast                 kubernetes.io/aws-ebs   Delete          Immediate              false                  19s
standard (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  42h

La storage class viene creata anche se il plugin non è disponibile. E' solo al momento di creazione del PVC e Pod che si presentano dei problemi.

Si possono avere molte Storage Classee configurate. I parametri di ciascuna dipendono dal plugin del provisioner.

Per esempio:

vim sc-secure.yml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: portworx-db-secure
provisioner: kubernetes.io/portworx-volume
parameters:
  fs: "xfs"
  block_size: "32"
  repl: "2"
  snap_interval: "30"
  io-priority: "medium"
  secure: "true"

Una StorageClass è un oggetto immutabile. Non si può modificare, solo cancellare e ricreare.

Le fasi d'uso sono:

  1. Creare il cluster Kubernetes
  2. Installare i necessari plugin per lo storage
  3. Creare una StorageClass
  4. Creare un PVC che si riferisce alla StorageClass
  5. Creare un Pod che usa un volume basato sul PVC

Non occorre quindi creare un oggetto PV, che è sostituito dalla StorageClass.

Esercizio Demo

Creare una StorageClass

Preparare la directory e creare il file di manifest:

mkdir -p ~/ex/sc
cd ~/ex/sc
vim google-sc.yml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
reclaimPolicy: Retain

Applicare il file di manifest:

kubectl apply -f google-sc.yml

Verifica:

kubectl get sc
kubectl describe sc slow

Creare un PVC

Il file di manifest:

vim google-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-ticket
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: slow
  resources:
    requests:
      storage: 25Gi

Applicare il file di manifest:

kubectl apply -f google-pvc.yml

Verificare:

kubectl get pvc
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pv-ticket   Pending                                      slow           3s

Notare lo stato Pending. Non abbiamo il driver CSI installato ed è in attesa che venga installato.

Ctreare un Pod

Il file fi manifest:

vim google-pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: class-pod
spec:
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: pv-ticket
  containers:
  - name: ubuntu-ctr
    image: ubuntu:latest
    command:
    - /bin/bash
    - "-c"
    - "sleep 60m"
    volumeMounts:
    - mountPath: /data
      name: data

Applicare il file di manifest:

kubectl apply -f google-pod.yml

Verifica:

kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
class-pod   0/1     Pending   0          56s

Anch'esso è nello stato Pending.

Ispezionandolo con:

kubectl describe pod class-pod

Notiamo che:

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  3m5s  default-scheduler  0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.

Di più non possiamo fare con Kind.

Ripoliamo l'esercizio:

kubectl delete -f google-pod.yml
kubectl delete -f google-pvc.yml
kubectl delete -f google-sc.yml