Introduction
Exécuter des conteneurs en production est simple, mais exploiter des charges de travail avec état de façon fiable exige une bonne maîtrise des primitives de stockage de Kubernetes. Ce guide parcourt les PersistentVolume (PV) – Persistent Volume (volume persistant), les PersistentVolumeClaim (PVC) – Persistent Volume Claim (revendication de volume persistant) et les StorageClass avec de vrais manifestes, des commandes de vérification et les modes de défaillance les plus fréquents que vous rencontrerez en passant d'un cluster local à un environnement de type production.
Le public visé comprend les développeurs, consultants DevOps et équipes techniques de startups qui doivent passer du concept à la validation locale rapidement. À la fin, vous serez capable de créer un PV, de le demander via un PVC, de laisser une StorageClass le provisionner dynamiquement, et de confirmer qu'un Pod peut lire et écrire des données qui survivent aux redémarrages du Pod.
Vue d'ensemble du flux de travail
1. Identifier les ressources à créer
| Ressource | Objectif | Champs typiques du manifeste |
|---|---|---|
| PersistentVolume | Objet de stockage à l'échelle du cluster (provisionnement statique) | capacity.storage, accessModes, persistentVolumeReclaimPolicy, hostPath.path ou nfs.server |
| PersistentVolumeClaim | Demande de stockage dans un namespace | resources.requests.storage, accessModes, storageClassName |
| StorageClass | Modèle de provisionnement dynamique | provisioner, parameters, reclaimPolicy, volumeBindingMode |
| Pod / Deployment | Consommateur qui monte le PVC | volumes.persistentVolumeClaim.claimName, volumeMounts.mountPath |
2. Vérifier chaque étape avec kubectl
# Lister tous les PV et leur état
kubectl get pv -o wide
# Lister les PVC dans le namespace courant
kubectl get pvc -o wide
# Afficher les StorageClass disponibles dans le cluster
kubectl get storageclass
# Décrire un PVC spécifique pour voir les événements de liaison
kubectl describe pvc my-data-pvc
# Décrire le PV lié
kubectl describe pv <pv-name>
# Vérifier les événements du Pod et l'état du montage
kubectl describe pod my-app-xyz
3. Scénarios d'échec courants et comment les repérer
| Symptôme | Cause probable | Commande de diagnostic | Correctif |
|---|---|---|---|
PVC reste Pending | Aucune StorageClass correspondante ou volumeBindingMode: WaitForFirstConsumer sans Pod planifié | kubectl describe pvc <name> affiche Events: FailedBinding | S'assurer qu'une StorageClass existe, définir correctement storageClassName, ou créer un Pod qui référence le PVC |
PV Available mais PVC Pending | Incompatibilité des accessModes (ex. PV ReadWriteOnce vs PVC ReadWriteMany) | kubectl get pv,pvc -o custom-columns=NAME:.metadata.name,ACCESS:.spec.accessModes | Aligner les accessModes sur les deux objets |
Pod bloqué en ContainerCreating | Erreur de permission de montage du volume ou nœud ne disposant pas du volume provisionné | kubectl describe pod <name> montre MountVolume.SetUp failed | Vérifier les labels du nœud, les logs du driver CSI, et fsGroup dans le securityContext du Pod |
| Données perdues après redémarrage du Pod | persistentVolumeReclaimPolicy: Delete sur un PV statique, ou utilisation d'emptyDir par erreur | kubectl get pv <name> -o jsonpath='{.spec.persistentVolumeReclaimPolicy}' | Utiliser Retain pour les PV statiques, s'assurer que le PVC est lié à un PV avec Retain |
Provisionnement dynamique échoue avec ProvisioningFailed | Driver CSI non installé, mauvais nom de provisioner, ou quota cloud épuisé | kubectl describe pvc <name> affiche l'événement ProvisioningFailed | Installer le bon driver CSI, vérifier que provisioner correspond au nom du driver, contrôler les quotas du fournisseur cloud |
Plan pilote local
1. Mettre en place un cluster minimal (kind / minikube / k3d)
# Exemple avec kind
kind create cluster --name storage-demo
kubectl cluster-info --context kind-storage-demo
2. Installer un driver CSI local pour le provisionnement dynamique (optionnel mais réaliste)
# Driver CSI hostpath pour kind
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-host-path/master/deploy/kubernetes-1.24/deploy.yaml
3. Créer une StorageClass qui utilise le driver hostpath
# storageclass-hostpath.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-hostpath
provisioner: hostpath.csi.k8s.io
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
parameters:
type: directory
Appliquer et vérifier :
kubectl apply -f storageclass-hostpath.yaml
kubectl get storageclass local-hostpath
4. Demander du stockage avec un PVC
# pvc-data.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: local-hostpath
kubectl apply -f pvc-data.yaml
kubectl get pvc data-pvc -w # surveiller jusqu'à ce que STATUS devienne Bound
5. Déployer une charge de travail qui monte le PVC
# deployment-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: storage-writer
spec:
replicas: 1
selector:
matchLabels:
app: storage-writer
template:
metadata:
labels:
app: storage-writer
spec:
containers:
- name: writer
image: busybox:1.36
command: [
"sh",
"-c",
"while true; do echo $(date) >> /data/out.txt; sleep 5; done"
]
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: data-pvc
kubectl apply -f deployment-app.yaml
kubectl rollout status deployment/storage-writer
6. Valider l'écriture et la persistance
# Récupérer le nom du pod
POD=$(kubectl get pods -l app=storage-writer -o jsonpath='{.items[0].metadata.name}')
# Inspecter le fichier à l'intérieur du conteneur
kubectl exec $POD -- cat /data/out.txt
# Supprimer le pod pour forcer sa recréation
kubectl delete pod $POD
# Attendre le nouveau pod et vérifier que les données ont survécu
kubectl rollout status deployment/storage-writer
NEW_POD=$(kubectl get pods -l app=storage-writer -o jsonpath='{.items[0].metadata.name}')
kubectl exec $NEW_POD -- cat /data/out.txt
Si les horodatages se suivent sans interruption, le PV a survécu au redémarrage du Pod.
7. Simuler un échec : modifier le PVC pour demander ReadWriteMany
# pvc-data-rwm.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc-rwm
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
storageClassName: local-hostpath
kubectl apply -f pvc-data-rwm.yaml
kubectl get pvc data-pvc-rwm
Le PVC restera Pending car le driver hostpath ne supporte que ReadWriteOnce. La sortie de describe affichera FailedBinding avec un message indiquant des modes d'accès incompatibles — exactement le scénario que vous rencontrerez en migrant vers un système de fichiers réseau qui prend en charge ReadWriteMany.
Conclusion
Traiter la configuration du stockage comme du code testable — et non comme un copier‑coller unique — est la méthode la plus sûre pour éviter les surprises dans les pipelines CI/CD et les clusters de production. Le flux ci‑dessus vous permet de :
- Définir une StorageClass adaptée à votre infrastructure (hostpath local, CSI cloud, NFS, etc.).
- Demander du stockage avec un PVC qui exprime la capacité et le mode d'accès exacts dont vous avez besoin.
- Vérifier la liaison avec
kubectl get pvcetkubectl describe pvc. - Monter le PVC dans une vraie charge de travail et confirmer que les données survivent à la recréation du Pod.
- Casser volontairement la demande (mauvais mode d'accès, StorageClass manquante, quota épuisé) pour observer les messages d'erreur exacts que vous devrez dépanner sous pression.
Prochaines étapes pour un déploiement de niveau production :
- Remplacer le driver hostpath par le driver CSI de votre fournisseur cloud (EBS, Persistent Disk, Azure Disk, etc.).
- Définir
volumeBindingMode: WaitForFirstConsumerpour un provisionnement tenant compte de la topologie. - Utiliser
reclaimPolicy: Retainpour les données critiques et mettre en place une stratégie de sauvegarde (Velero, snapshots CSI). - Ajouter
fsGroupetrunAsUserdans lesecurityContextdu Pod pour éviter les problèmes de permissions sur les volumes partagés.
En exécutant les commandes localement d'abord, vous transformez des concepts abstraits en comportement observable, rendant le passage en staging et en production prévisible plutôt qu'espéré.