Volumes persistants
Dans les articles précédents, nous avons vu la notion de volumes. C’est ce qui permet d’apporter des données aux pods, par exemple de la configuration via des ConfigMap ou des identifiants via des Secrets. Mais les volumes que nous avons vu jusqu’ici étaient temporaires. C’est-à-dire tout ce qui est écrit dessus disparaît quand le pod disparaît. Or il y a des applications qui ont besoin de persistance de données. Par exemple, on ne peut pas perdre les données d’une base de données SQL dès qu’il arrive un souci au pod.
Dans ces cas, nous avons besoin de nouveaux objets Kubernetes qui nous apportent des volumes persistants : les PV, les PVC et les Storage Class.
Un PV (Persistent Volume) représente le stockage (par exemple un disque SSD) disponible à utiliser par des pods sur un cluster. Chaque PV contient les informations concernant ses capacités (quel type de disque, quelle taille, où est-ce qu’il se trouve, etc.) Mais un pod ne demande pas directement un PV, il passe d’abord par un PVC.
Un PVC (Persistent Volume Claim) est l’objet qui représente ce que demande un utilisateur comme stockage. Et c’est un algorithme de contrôle k8s qui se charge de désigner quel PV va correspondre à ce PVC. Si un utilisateur demande un PVC de 1Gi et qu’il n’y a qu’un PV de 10Gi de disponible, k8s va associer le PV de 10Gi au PVC demandant 1Gi. La plupart du temps, pour éviter ce genre de problèmes, les PV ne sont pas créés de manière statique au préalable de la demande de PVC. On attend qu’un utilisateur demande un PVC d’une certaine taille et avec certaines caractéristiques pour que k8s puisse satisfaire cette demande avec un PV qu’il va créer dynamiquement. Pour le faire, l’administrateur doit spécifier des StorageClass. Une StorageClass permet de décrire comment on peut demander des volumes persistants sur le cluster k8s. Par exemple, on peut avoir une StorageClass qui crée des disques SSD normaux, une qui crée des disques SSD très performants, une autre qui crée des partages de fichiers NFS ou SMB. Lorsqu’un utilisateur veut avoir un volume SSD de 1Gi par exemple, il doit créer un PVC qui fait référence à la StorageClass qui correspond à ses besoins, et un contrôleur k8s va créer le PV qui va correspondre à ce PVC, et lier les deux.
Création statique d’un Persistent Volume
Nous allons d’abord commencer par créer un volume persistant de manière statique pour comprendre comment marche la mécanique d’association des PV et PVC, ainsi que pour voir concrètement la persistance des volumes.
Créons d’abord le PV :
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-data
spec:
storageClassName: "local"
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/opt/data"
Le PV que nous voulons créer est d’une capacité de 1Gi, avec un accessModes de ReadWriteOnce (nous allons voir ces détails plus tard), et pour le fournir, nous demandons à k8s d’utiliser hostPath, c’est-à-dire qu’il sera créé sur le noeud sur lequel il sera utilisé, sur le chemin /opt/data.
La StorageClass “local” n’existe pas, mais elle nous sert afin de permettre la correspondance entre ce PV et le PVC que nous allons créer plus tard.
Quand nous créons le PV :
kubectl apply -f pv-data.yaml
kubectl get pv pv-data
NAME CAPACITY STATUS STORAGECLASS
pv-data 1Gi Available local
Il est bien dans l’état Available.
Maintenant nous pouvons créer le PVC :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-data
spec:
storageClassName: "local"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
kubectl apply -f pvc-data.yaml
Tout ce que nous avons demandé ici, c’est de créer un PVC d’une taille de 1Gi.
Quand on regarde le PVC :
kubectl get pvc pvc-data
NAME STATUS VOLUME CAPACITY STORAGECLASS
pvc-data Bound pv-data 1Gi local
On voit bien que le PVC est lié au PV pv-data qui correspond à la taille de 1Gi demandée par le PVC. Si on avait demandé une taille plus grande, k8s n’aurait pas assigné ce PV à notre PVC.
Et pour confirmer la liaison dans l’autre sens aussi, on peut revoir l’état du PV :
kubectl get pv pv-data
NAME CAPACITY STATUS CLAIM STORAGECLASS
pv-data 1Gi RWO Bound test/pvc-data local
On voit bien que le PV a été attaché au PVC pvc-data qui se trouve dans le namespace test. Et que le PV est passé au statut Bound.
Nous allons maintenant créer un pod qui va utiliser ce PV/PVC :
apiVersion: v1
kind: Pod
metadata:
labels:
run: pvc-pod
name: pvc-pod
spec:
containers:
- image: busybox:latest
name: pvc-pod
args:
- sleep
- "3600"
volumeMounts:
- name: data
mountPath: "/data"
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-data
Nous avons déclaré le volume qui s’appelle data et qui fait référence au PVC pvc-data. Puis nous l’avons monté sur le container pvc-pod sur le chemin /data.
On le lance et on voit que le dossier /data est bien là :
kubectl apply -f pvc-pod.yaml
kubectl exec pvc-pod -- ls -l /
drwxr-xr-x 2 root root 4096 Jan 2 10:50 data
Pour vérifier que le volume est bien persistent, on va créer un fichier dans le volume data :
kubectl exec pvc-pod -- touch /data/file
kubectl exec pvc-pod-2 -- ls /data/
file
On supprime le pod :
kubectl delete -f pvc-pod.yaml
Puis on créé un nouveau pod qui va s’appeler pvc-pod-2 et qui monte le volume data de la même manière que pvc-pod :
apiVersion: v1
kind: Pod
metadata:
labels:
run: pvc-pod
name: pvc-pod-2
spec:
containers:
- image: busybox:latest
name: pvc-pod
args:
- sleep
- "3600"
volumeMounts:
- name: data
mountPath: "/data"
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-data
kubectl apply -f pvc-pod-2.yaml
On regarde dans le dossier /data, et on voit que le fichier qu’on a créé dans le premier pod existe toujours, donc que la donnée est bien persistée :
kubectl exec pvc-pod-2 -- ls /data/
file
Conclusion
Dans cet article, nous avons vu ce qu’étaient les PV, les PVC et les Storage Class. Nous avons vu aussi comment créer de manière statique un PV, lui lier un PVC, et créer un pod qui utilise ce PVC. Mais généralement, on ne veut pas se soucier de créer un PV à chaque fois qu’un pod a besoin d’un volume. On préfère demander un PVC, et c’est la Storage Class et son provisioner associé qui se charge de créer s’il le peut un PV qui correspond à la spécification du PV. C’est ce qu’on va voir dans le prochain article.