Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Gestion dynamique du stockage avec les StorageClass

23 min de lecture

logo kubernetes

Dans un guide précédent, nous avons exploré comment Kubernetes gère le stockage, notamment à travers les solutions intégrées et l’utilisation de CSI (Container Storage Interface). Nous avons abordé les concepts de stockage éphémère et persistant, ainsi que les différents types de volumes disponibles. Pour approfondir cette thématique, il est essentiel de comprendre le rôle de la ressource StorageClasses.

Dans ce guide, nous allons détailler leur fonctionnement, leur création et leur gestion pour optimiser l’utilisation du stockage dans vos déploiements Kubernetes.

Avant de manipuler les StorageClasses dans Kubernetes, il est essentiel de disposer d’un environnement fonctionnel et des outils adéquats. Voici ce dont vous aurez besoin :

kubectl est l’outil en ligne de commande indispensable pour gérer un cluster Kubernetes. Il permet de :

  • Appliquer des fichiers de configuration YAML
  • Lister et vérifier l’état des StorageClasses, PV et PVC
  • Debugger les éventuels problèmes liés au stockage

Helm est un gestionnaire de paquets pour Kubernetes, qui facilite l’installation et la gestion des applications complèxes. Il est souvent utilisé pour déployer des provisionneurs de stockage CSI (Container Storage Interface) dans un cluster.

Pour tester les StorageClasses et le provisionnement dynamique de volumes, vous devez disposer d’un cluster Kubernetes fonctionnel. Deux options s’offrent à vous :

  • Un cluster en production ou hébergé sur le cloud (AWS EKS, Azure AKS, Google GKE, OpenShift, etc.)
  • Un cluster local pour les tests et l’apprentissage Minikube est une solution simple à mettre en place sur une machine locale.

Vérifiez que votre cluster est bien opérationnel avec la commande :

Fenêtre de terminal
kubectl cluster-info
Kubernetes control plane is running at https://192.168.50.141:8443
CoreDNS is running at https://192.168.50.141:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Si votre cluster est en place, vous devriez voir une sortie indiquant l’adresse de l’API Kubernetes.

Un éditeur de code pour manipuler les fichiers YAML

Section intitulée « Un éditeur de code pour manipuler les fichiers YAML »

Pour éditer et appliquer vos fichiers de configuration Kubernetes, il est recommandé d’utiliser un éditeur de code adapté comme :

  • VS Code avec l’extension Kubernetes
  • Vim ou Nano si vous préférez un éditeur en ligne de commande
  • IntelliJ IDEA avec le plugin Kubernetes

Sans StorageClass, le processus de stockage est statique : un administrateur doit d’abord créer un PersistentVolume (PV), puis un PersistentVolumeClaim (PVC) doit le réclamer. Mais cette méthode pose plusieurs problèmes :

  • Complexité : il faut créer et gérer chaque volume manuellement.
  • Manque de flexibilité : si plusieurs applications ont besoin de stockage, il faut anticiper et créer les volumes à l’avance.
  • Moins d’automatisation : Kubernetes ne peut pas provisionner de nouveaux volumes automatiquement.

Avec une StorageClass, Kubernetes peut créer des volumes à la demande, en fonction des besoins de l’application. L’administrateur définit une fois les règles et Kubernetes gère le reste !

Pour les exemples de ce guide, nous allons utiliser un serveur NFS pour le stockage persistant. Voici comment installer un serveur NFS sur une machine Ubuntu :

  1. Installer le serveur NFS :

    Fenêtre de terminal
    sudo apt update
    sudo apt install nfs-server

    Si vous ne maitrisez pas le gestionnaire de paquets apt, je vous recommande de lire mon guide sur apt pour mieux comprendre son fonctionnement.

  2. Créer un répertoire partagé :

    Fenêtre de terminal
    sudo mkdir -p /data
  3. Configurer le partage NFS :

    Fenêtre de terminal
    echo "/data *(rw,sync,no_subtree_check)" | sudo tee -a /etc/exports

    La redirection >> ne bénéficie pas des privilèges sudo. Utilisez tee -a pour écrire dans un fichier protégé.

  4. Redémarrer le serveur NFS :

    Fenêtre de terminal
    sudo systemctl restart nfs-kernel-server
  5. Vérifier que le partage est bien configuré :

    Fenêtre de terminal
    sudo exportfs
    /data <world>

Votre serveur NFS est maintenant prêt à être utilisé pour les exemples de StorageClasses.

De nombreux provisionneurs CSI sont disponibles pour Kubernetes, chacun permettant l’intégration avec différents systèmes de stockage. Voici quelques exemples notables :

  • AWS Elastic Block Store (EBS) : Permet l’utilisation des volumes EBS d’AWS comme stockage persistant dans Kubernetes.
  • Azure Disk Storage : Intègre les disques managés d’Azure pour une utilisation avec Kubernetes.
  • Google Persistent Disk : Offre une intégration avec les disques persistants de Google Cloud.
  • NFS (Network File System) : Permet l’utilisation de serveurs NFS existants pour le stockage persistant.

Pour une liste complète et à jour des provisionneurs CSI disponibles, vous pouvez consulter la documentation officielle de Kubernetes CSI.

L’installation d’un provisionneur NFS CSI permet à Kubernetes d’interagir avec un serveur NFS pour la gestion dynamique des volumes persistants. Voici comment procéder :

  1. Pré-requis :

    • Disposer d’un serveur NFS fonctionnel et accessible depuis le cluster Kubernetes.
  2. Déploiement du driver CSI NFS :

    • Utiliser le chart Helm fourni par le projet csi-driver-nfs :

      Fenêtre de terminal
      helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
      helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --namespace kube-system --version 4.12.0

      Note : Depuis la version 4.11.0, le préfixe v a été retiré des numéros de version du chart Helm. Vérifiez la dernière version sur le dépôt GitHub.

  3. Vérifier que le provisionneur est bien en place :

    Fenêtre de terminal
    kubectl get pods -n kube-system -o wide | grep nfs
    csi-driver-nfs-controller-0 5/5 Running 0 2m
    csi-driver-nfs-node-0-0 3/3 Running 0 2m

Au bout de quelques instants, le provisionneur CSI NFS devrait être déployé et opérationnel dans votre cluster.

Le driver NFS CSI (nfs.csi.k8s.io) est composé de deux éléments :

ComposantRôle
ControllerGère le provisionnement et la suppression des volumes
Node pluginMonte/démonte les volumes sur chaque nœud

Comportement lors du provisionnement dynamique :

  1. Un PVC référence une StorageClass avec provisioner: nfs.csi.k8s.io
  2. Le controller NFS CSI crée un sous-répertoire dans le partage NFS configuré
  3. Ce sous-répertoire porte le nom du PV généré (ex: pvc-8b6dcfbb-5556-...)
  4. Le PV est créé et lié au PVC
  5. Quand un Pod consomme le PVC, le node plugin monte le sous-répertoire NFS

Important : Le driver NFS CSI ne crée pas de serveur NFS. Il utilise un serveur NFS existant que vous devez configurer et maintenir séparément.

Le driver NFS CSI est adapté pour :

Cas d’usageRecommandation
Développement/Lab✅ Idéal — simple à mettre en place
Partage RWX multi-pods✅ Bon choix — NFS supporte nativement ReadWriteMany
Données partagées légères✅ Configurations, fichiers statiques, logs
Bases de données⚠️ Déconseillé — latence et performances insuffisantes
Workloads I/O intensifs❌ Préférez des solutions bloc (Ceph, Longhorn)
Haute disponibilité⚠️ Dépend de votre serveur NFS (SPOF potentiel)

Pour la production avec exigences de performance, privilégiez des solutions comme Ceph/Rook, Longhorn, ou les stockages managés cloud.

Avant de créer une StorageClass, il est essentiel de comprendre les paramètres clés qui la composent et leur rôle dans le provisionnement des volumes persistants.

Une StorageClass est une ressource Kubernetes qui définit les règles pour provisionner automatiquement des volumes persistants. Voici les paramètres clés d’une StorageClass et leur rôle :

  • provisioner : Définit le provisionneur de stockage utilisé.

    • Exemple : nfs.csi.k8s.io pour le driver NFS CSI. Vous pouvez trouver le nom du provisionneur dans la documentation du driver CSI.
  • parameters : Contient les configurations spécifiques au stockage.

    • server : Adresse du serveur NFS.
    • share : Chemin du partage NFS sur le serveur.
  • reclaimPolicy : Définit ce qu’il advient du volume une fois que le PersistentVolumeClaim (PVC) est supprimé.

    • Delete : Kubernetes supprime automatiquement le volume.
    • Retain : Le volume reste présent et doit être supprimé manuellement.
  • allowVolumeExpansion : Permet ou non l’agrandissement d’un volume après sa création (true ou false).

  • volumeBindingMode : Définit quand Kubernetes lie un PersistentVolume à un PersistentVolumeClaim.

    • Immediate (par défaut) : Le volume est créé dès la demande du PVC.
    • WaitForFirstConsumer : Kubernetes attend qu’un Pod consomme le PVC avant de créer le volume.

Pourquoi utiliser WaitForFirstConsumer ?

Ce mode est particulièrement utile dans plusieurs situations :

  1. Contraintes de topologie : Si votre stockage est lié à une zone ou un nœud spécifique (ex: disques locaux, zones AWS), le scheduler doit d’abord placer le Pod avant de provisionner le volume dans la bonne zone.
  2. Éviter le gaspillage : Le volume n’est créé que si un Pod en a réellement besoin, pas juste parce qu’un PVC existe.
  3. Cohérence Pod/Volume : Garantit que le volume sera accessible depuis le nœud où le Pod sera planifié.

Pour les stockages réseau comme NFS qui sont accessibles depuis tous les nœuds, Immediate convient généralement. Pour les stockages avec contraintes de localité, préférez WaitForFirstConsumer.

Dans un cluster Kubernetes, une StorageClass peut être marquée comme par défaut. Cette classe sera automatiquement utilisée pour tout PVC qui ne spécifie pas explicitement de storageClassName.

Pour voir quelle StorageClass est la classe par défaut :

Fenêtre de terminal
kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate true 2h
standard (default) rancher.io/local Delete WaitForFirstConsumer false 30d

La mention (default) indique la classe par défaut.

Pour définir une StorageClass comme défaut, ajoutez l’annotation suivante :

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
annotations:
storageclass.kubernetes.io/is-default-class: "true"
# ... reste de la configuration

Attention : Si aucune StorageClass par défaut n’existe et qu’un PVC ne spécifie pas de storageClassName, le PVC restera en Pending indéfiniment.

Maintenant que nous avons installé le provisionneur NFS CSI, nous allons créer une StorageClass qui utilisera ce driver pour provisionner des volumes dynamiquement.

  1. Créer un fichier storageclass-nfs.yaml :

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
    name: nfs-csi
    provisioner: nfs.csi.k8s.io
    parameters:
    server: 192.168.20.121 # Remplacer par l'adresse IP du serveur NFS
    share: /data
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    allowVolumeExpansion: true
    mountOptions:
    - nfsvers=4.1
  2. Appliquer la StorageClass dans Kubernetes :

    Fenêtre de terminal
    kubectl apply -f storageclass-nfs.yaml
  3. Vérifier que la StorageClass a été créée :

    Fenêtre de terminal
    kubectl get storageclass
    NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
    nfs-csi nfs.csi.k8s.io Delete Immediate true 2m

Une fois la StorageClass créée, elle peut être utilisée pour provisionner des volumes persistants dynamiquement à l’aide d’un PersistentVolumeClaim (PVC).

  1. Créer un fichier pvc-nfs.yaml :

    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: pvc-deployment-nfs
    namespace: default
    spec:
    accessModes:
    - ReadWriteMany # Accès en lecture/écriture pour plusieurs Pods
    resources:
    requests:
    storage: 10Gi
    storageClassName: nfs-csi # Utilisation de la StorageClass NFS définie précédemment

    Ce PVC demande 10 Go de stockage en ReadWriteMany, ce qui signifie qu’il peut être monté sur plusieurs Pods en même temps.

  2. Appliquer le PVC :

    Fenêtre de terminal
    kubectl apply -f pvc-nfs.yaml
  3. Vérifier que le PVC est bien lié à un volume :

    Fenêtre de terminal
    kubectl get pvc
    NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
    pvc-deployment-nfs Bound pvc-a7b9101f-644d-4bbd-8b7b-eaa8ced6f74a 10Gi RWX nfs-csi <unset> 8s

    Le statut Bound signifie que le volume a été créé et est prêt à être utilisé.

Avec cette StorageClass basée sur NFS CSI, Kubernetes peut provisionner dynamiquement des volumes persistants dès qu’une application en fait la demande, sans intervention manuelle.

  1. Créer un fichier deployment.yaml :

    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: deployment-nfs
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    name: deployment-nfs
    template:
    metadata:
    name: deployment-nfs
    labels:
    name: deployment-nfs
    spec:
    nodeSelector:
    "kubernetes.io/os": linux
    containers:
    - name: deployment-nfs
    image: mcr.microsoft.com/oss/nginx/nginx:1.19.5
    command:
    - "/bin/bash"
    - "-c"
    - set -euo pipefail; while true; do echo $(hostname) $(date) >> /mnt/nfs/outfile; sleep 1; done
    volumeMounts:
    - name: nfs
    mountPath: "/mnt/nfs"
    readOnly: false
    volumes:
    - name: nfs
    persistentVolumeClaim:
    claimName: pvc-deployment-nfs
  2. Appliquer le déploiement :

    Fenêtre de terminal
    kubectl apply -f deployment.yaml
  3. Vérifier que le déploiement est en cours :

    Fenêtre de terminal
    kubectl get pods
    deployment-nfs-7fbbf89668-md8gc 1/1 Running 0 1s

Le déploiement est en cours et le pod est en train de consommer le volume provisionné par la StorageClass NFS.

Vérifiez le contenu du dossier /data sur le serveur NFS pour voir les fichiers générés par le pod.

Fenêtre de terminal
ls -al /data
drwxrwxrwx 3 nobody nogroup 4096 mars 4 18:38 .
drwxr-xr-x 24 root root 4096 janv. 27 13:06 ..
drwxr-xr-x 2 root root 4096 mars 4 18:38 pvc-8b6dcfbb-5556-41f3-9434-025784808f22

On retroue le dossier créé par le PVC, qui contient les fichiers générés par le pod.

Fenêtre de terminal
cat /data/pvc-8b6dcfbb-5556-41f3-9434-025784808f22/outfile
deployment-nfs-7fbbf89668-md8gc Tue Mar 4 18:38:54 UTC 2025
deployment-nfs-7fbbf89668-md8gc Tue Mar 4 18:38:55 UTC 2025
deployment-nfs-7fbbf89668-md8gc Tue Mar 4 18:38:56 UTC 2025

Le pod écrit bien dans le fichier outfile du volume NFS.

Passons le replica à 2 pour voir que les deux pods peuvent écrire dans le même fichier.

Fenêtre de terminal
kubectl scale deployment deployment-nfs --replicas=2

Vérifiez que les deux pods écrivent bien dans le même fichier.

Fenêtre de terminal
cat /data/pvc-8b6dcfbb-5556-41f3-9434-025784808f22/outfile
deployment-nfs-7fbbf89668-xktb6 Tue Mar 4 18:42:08 UTC 2025
deployment-nfs-7fbbf89668-md8gc Tue Mar 4 18:42:09 UTC 2025
deployment-nfs-7fbbf89668-xktb6 Tue Mar 4 18:42:09 UTC 2025
deployment-nfs-7fbbf89668-md8gc Tue Mar 4 18:42:10 UTC 2025
deployment-nfs-7fbbf89668-xktb6 Tue Mar 4 18:42:10 UTC 2025

Les deux pods écrivent bien dans le même fichier, ce qui prouve que le volume est bien partagé entre les deux pods.

L’utilisation des StorageClasses dans Kubernetes peut parfois poser des problèmes : volumes qui ne se créent pas, erreurs de provisionnement, ou encore PVC en attente (Pending). Ce chapitre présente les méthodes de diagnostic et les solutions aux erreurs courantes.

Avant toute chose, il faut s’assurer que la StorageClass utilisée existe bien dans le cluster :

Fenêtre de terminal
kubectl get storageclass

Exemple de sortie :

NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-storage nfs.csi.k8s.io Retain Immediate true 2h

Si votre StorageClass n’apparaît pas, assurez-vous qu’elle a bien été créée :

Fenêtre de terminal
kubectl describe storageclass <nom-de-la-storageclass>

Si la StorageClass est introuvable, appliquez à nouveau son fichier YAML :

Fenêtre de terminal
kubectl apply -f storageclass.yaml

Si un PersistentVolumeClaim (PVC) reste bloqué en Pending, vérifiez son état :

Fenêtre de terminal
kubectl get pvc

Exemple de sortie avec un problème :

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Pending nfs-storage 3m

Si le PVC reste en Pending, exécutez :

Fenêtre de terminal
kubectl describe pvc pvc-nfs

Vous devriez voir des événements indiquant la raison du blocage.

Exemple d’erreur :

Warning ProvisioningFailed 2m csi-nfs-controller failed to provision volume with StorageClass "nfs-storage":
provisioner nfs.csi.k8s.io failed to create volume: connection refused

Voici les raisons les plus fréquentes pour lesquelles un PVC reste bloqué :

CauseDiagnosticSolution
StorageClass inexistantekubectl get sc ne liste pas la classeCréer la StorageClass ou corriger le nom
Pas de StorageClass par défautPVC sans storageClassName + pas de défautAjouter storageClassName au PVC ou définir une classe par défaut
Provisioner CSI absentPods CSI non Running dans kube-systemInstaller/redémarrer le driver CSI
Serveur NFS inaccessibleEvents : “connection refused”Vérifier connectivité réseau et firewall
Export NFS incorrectEvents : “permission denied” ou “no such file”Vérifier /etc/exports et exportfs -v
Options de montage incompatiblesEvents : “mount failed”Ajuster mountOptions dans la StorageClass
Droits insuffisants côté NFSErreur de permission lors de l’écritureVérifier les permissions du répertoire partagé
WaitForFirstConsumerStatus “WaitForFirstConsumer”Normal — le PVC attend qu’un Pod le consomme

Pour identifier rapidement la cause :

Fenêtre de terminal
# 1. Vérifier les events du PVC
kubectl describe pvc <nom-pvc> | grep -A 10 Events
# 2. Vérifier les logs du provisioner
kubectl logs -l app=csi-nfs-controller -n kube-system --tail=50
# 3. Tester la connectivité NFS depuis un nœud
showmount -e <NFS_SERVER_IP>

Les erreurs liées aux volumes sont souvent enregistrées dans les événements Kubernetes. Pour afficher les événements récents :

Fenêtre de terminal
kubectl get events --sort-by=.metadata.creationTimestamp

Vous pouvez aussi vérifier les erreurs liées au driver CSI :

Fenêtre de terminal
kubectl logs -l app=csi-nfs-controller -n kube-system

Si vous utilisez un autre provisionneur (AWS, Azure, Google Cloud), remplacez csi-nfs-controller par le nom du provisionneur concerné.

Si un PVC est bien créé mais que le pod ne parvient pas à l’utiliser, vérifiez l’état du PersistentVolume (PV) :

Fenêtre de terminal
kubectl get pv

Si le PV existe mais est en état Released ou Failed, il ne pourra plus être réutilisé.

Solution : Supprimez le PV et laissez Kubernetes en créer un nouveau :

Fenêtre de terminal
kubectl delete pv <nom-du-pv>

Si un pod ne parvient pas à monter un volume, vous pouvez tester manuellement si le stockage fonctionne. Par exemple, pour un volume NFS :

  1. Connectez-vous à un pod en cours d’exécution :

    Fenêtre de terminal
    kubectl run -it --rm --image=busybox test-pod -- /bin/sh
  2. Essayez de monter le partage NFS :

    Fenêtre de terminal
    mount -t nfs <NFS_SERVER_ADDRESS>:<NFS_SHARE_PATH> /mnt

Si cette commande échoue, le problème vient du serveur NFS.

Si le provisionneur CSI semble bloqué, vous pouvez redémarrer ses pods :

Fenêtre de terminal
kubectl delete pod -l app=csi-nfs-controller -n kube-system

Cela forcera Kubernetes à recréer les composants liés au provisionneur.

  1. StorageClass = provisionnement dynamique : Plus besoin de créer les PV manuellement, Kubernetes les crée à la demande.

  2. volumeBindingMode: WaitForFirstConsumer : Indispensable pour les stockages avec contraintes de topologie (zones, nœuds spécifiques).

  3. StorageClass par défaut : Si un PVC n’indique pas de storageClassName, Kubernetes utilise la classe marquée is-default-class: "true".

  4. NFS CSI crée des sous-répertoires : Chaque volume dynamique devient un dossier dans le partage NFS, nommé d’après le PV.

  5. NFS = RWX natif : Idéal pour partager des données entre plusieurs Pods, moins adapté aux workloads I/O intensifs.

  6. PVC Pending = diagnostic obligatoire : Vérifiez la StorageClass, le provisioner CSI, la connectivité NFS et les permissions.

  7. reclaimPolicy: Retain : Conserve le volume après suppression du PVC — utile pour les données critiques mais nécessite un nettoyage manuel.

Dans ce guide, nous avons exploré comment utiliser une StorageClass pour gérer dynamiquement le stockage persistant dans Kubernetes. Nous avons mis en place un serveur NFS, configuré un PVC et intégré le volume dans un Deployment. Enfin, nous avons testé la persistance des données après la suppression d’un Pod.

Cette approche avec NFS est idéale pour un environnement de développement ou des charges de travail légères, mais en production, d’autres solutions plus performantes et résilientes sont recommandées :

SolutionTypeCas d’usage
Ceph/RookBloc, fichier, objetClusters on-premise nécessitant haute disponibilité
LonghornBloc distribuéKubernetes natif, snapshots, backups intégrés
OpenEBS/MayastorBloc NVMePerformances élevées, stockage local distribué
Stockage cloud managéSelon providerEBS (AWS), Azure Disk, Persistent Disk (GCP)

Note : Le driver GlusterFS in-tree a été déprécié en Kubernetes 1.25 et supprimé en 1.26. Le driver CSI GlusterFS n’est plus maintenu activement. Préférez les solutions ci-dessus pour les nouveaux déploiements.

Ces technologies, intégrables avec Kubernetes via CSI (Container Storage Interface), permettent d’aller plus loin dans l’automatisation et la gestion avancée du stockage.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn