🎯 Objectif : À la fin de ce chapitre, tu sauras persister les données de tes Pods avec les PersistentVolumes et choisir le bon type de volume selon le contexte. ⏱️ Durée estimée : 50 minutes | Niveau : Intermédiaire
Par défaut, quand un conteneur Kubernetes meurt, tout ce qu’il contenait disparaît avec lui. Fichiers uploadés, base de données, cache — pouf, volatilisé. C’est le comportement normal : un conteneur est éphémère par design.
Sauf qu’en production, tu as besoin de garder des données entre les redémarrages. Une base PostgreSQL qui perd ses tables à chaque déploiement, ça ne fait rire personne. C’est là qu’interviennent les Volumes Kubernetes — le mécanisme qui permet de découpler le cycle de vie des données de celui du conteneur.
Pourquoi c’est important
Sans volumes, tu ne peux pas faire tourner d’application stateful sur Kubernetes. Et en entreprise, la majorité des workloads critiques sont stateful : bases de données, files de messages, stockage de fichiers, caches persistants.
Le système de volumes de Kubernetes résout trois problèmes fondamentaux :
- Persistance : les données survivent à la mort du Pod
- Partage : plusieurs conteneurs dans un même Pod accèdent aux mêmes fichiers
- Découplage : le développeur demande du stockage sans savoir quel disque physique est utilisé
🧠 À retenir : Kubernetes sépare volontairement celui qui fournit le stockage (l’admin/le cloud) de celui qui le consomme (le développeur). C’est le pattern PV/PVC, et c’est la clé de tout ce chapitre.
Comprendre les types de volumes
Kubernetes propose plusieurs types de volumes. Voici les trois que tu utiliseras le plus souvent.
emptyDir — le volume éphémère
emptyDir crée un répertoire vide à la naissance du Pod. Il est partagé entre tous les conteneurs du Pod, mais détruit quand le Pod disparaît. C’est utile comme espace de travail temporaire entre conteneurs sidecar.
Voici un Pod avec deux conteneurs qui partagent un volume emptyDir — le premier écrit, le second lit :
apiVersion: v1
kind: Pod
metadata:
name: pod-emptydir
spec:
containers:
- name: writer
image: busybox:1.36
command: ["sh", "-c", "echo 'hello' > /data/msg.txt && sleep 3600"]
volumeMounts:
- name: shared
mountPath: /data
- name: reader
image: busybox:1.36
command: ["sh", "-c", "sleep 5 && cat /data/msg.txt && sleep 3600"]
volumeMounts:
- name: shared
mountPath: /data
volumes:
- name: shared
emptyDir: {}
💡 Tip DevOps : emptyDir: { medium: Memory } monte le volume en tmpfs (RAM). Plus rapide pour du cache, mais ça consomme la mémoire du node — à dimensionner avec soin.
hostPath — monter un chemin du node
hostPath monte un répertoire du node hôte dans le Pod. Pratique pour accéder aux logs système ou au socket Docker, mais ça crée un couplage fort avec le node physique.
⚠️ Attention : hostPath donne un accès direct au filesystem du node. En environnement multi-tenant, c’est un vecteur d’attaque. En production, préfère toujours les PV/PVC.
PersistentVolume (PV) et PersistentVolumeClaim (PVC)
C’est le mécanisme central. Le PV représente un stockage réel (disque cloud, NFS, Ceph…). Le PVC est la demande du développeur. Kubernetes fait le matching automatiquement.
L’admin crée d’abord un PV qui décrit le stockage disponible :
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-data
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
server: 192.168.1.100
path: /exports/data
Le développeur crée ensuite un PVC pour réclamer de l’espace, puis le monte dans son Pod :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-app-data
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pod-with-pvc
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-app-data
Les access modes définissent comment le volume est partagé : ReadWriteOnce (RWO) pour un seul node, ReadOnlyMany (ROX) en lecture seule multi-nodes, ReadWriteMany (RWX) en lecture/écriture multi-nodes, et ReadWriteOncePod (RWOP, K8s 1.27+) pour un seul Pod exclusif.
StorageClasses — le provisionnement dynamique
Créer chaque PV à la main, ça ne passe pas à l’échelle. Les StorageClasses automatisent la création : quand un PVC référence une StorageClass, Kubernetes provisionne le PV automatiquement.
Voici une StorageClass pour des disques SSD sur GKE, suivie d’un PVC qui l’utilise :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: pd-csi.storage.gke.io
parameters:
type: pd-ssd
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-database
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
💡 Tip DevOps : volumeBindingMode: WaitForFirstConsumer retarde la création du PV jusqu’à ce qu’un Pod le consomme. Indispensable en cluster multi-zones pour éviter qu’un PV se retrouve dans une zone sans node.
Commandes essentielles
Voici les commandes kubectl que tu utiliseras au quotidien pour gérer les volumes :
# Lister les StorageClasses disponibles
kubectl get storageclass
# Vérifier l'état d'un PVC (doit être "Bound")
kubectl get pvc pvc-database
# Voir les PV et leur reclaim policy
kubectl get pv -o wide
# Diagnostiquer un PVC bloqué en Pending
kubectl describe pvc pvc-database
# Agrandir un PVC (si allowVolumeExpansion: true)
kubectl patch pvc pvc-database -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'
🧠 À retenir : Un PVC en état Pending signifie qu’aucun PV ne correspond à sa demande (taille, access mode, StorageClass). kubectl describe pvc te donnera la raison exacte.
Cas concret entreprise
🔥 Cas réel : Tu déploies une stack de monitoring (Prometheus + Grafana) sur un cluster EKS. Prometheus ingère des métriques et a besoin de stockage persistant pour les conserver entre les redémarrages.
Tu crées une StorageClass gp3 avec reclaimPolicy: Retain (tu ne veux surtout pas perdre tes métriques si quelqu’un supprime un PVC par erreur). Le StatefulSet Prometheus utilise un volumeClaimTemplate qui génère automatiquement un PVC par replica :
volumeClaimTemplates:
- metadata:
name: prometheus-data
spec:
storageClassName: gp3-retain
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
Chaque replica Prometheus obtient son propre PVC (prometheus-data-prometheus-0, prometheus-data-prometheus-1…). Si un Pod crash, il se rattache au même PVC au redémarrage. Les données sont intactes.
Grafana, lui, utilise un simple PVC de 5Gi pour stocker ses dashboards et sa base SQLite. Un seul replica suffit, donc RWO convient parfaitement.
Pièges fréquents
PVC bloqué en Pending — C’est le problème numéro un. Causes habituelles : pas de StorageClass par défaut, taille demandée supérieure à ce qui est dispo, ou access mode incompatible avec le provisioner (beaucoup de providers cloud ne supportent pas RWX nativement).
⚠️ Attention : Supprimer un PVC avec reclaimPolicy: Delete supprime aussi le disque sous-jacent et toutes ses données. Irréversible. En production, utilise Retain pour les données critiques.
hostPath en production — Ne fais pas ça. Ton Pod sera lié à un node spécifique, et si le node tombe, tes données aussi. Sans parler des implications sécurité.
Oublier le reclaim policy — Par défaut, beaucoup de StorageClasses utilisent Delete. Si tu supprimes ton PVC de base de données “pour nettoyer”, tu perds tout. Vérifie toujours la reclaim policy avant de supprimer quoi que ce soit.
Confondre la taille du PVC et l’espace réel — Un PVC de 100Gi ne garantit pas que le filesystem aura exactement 100Gi. L’overhead du filesystem et du provisioner peut réduire l’espace utilisable. Prévois toujours une marge de 10-15%.
Exercice
Déploie un Pod PostgreSQL avec du stockage persistant :
- Crée un PVC de 1Gi nommé
pvc-postgres - Déploie un Pod PostgreSQL qui monte ce PVC sur
/var/lib/postgresql/data - Connecte-toi au Pod, crée une table et insère des données
- Supprime le Pod (pas le PVC !), recrée-le avec le même PVC
- Vérifie que tes données sont toujours là
Pour aller plus loin : crée une StorageClass avec reclaimPolicy: Retain, associe-la au PVC, supprime le PVC et observe l’état du PV — il doit passer en Released au lieu d’être supprimé.
# Commandes utiles pour l'exercice
kubectl apply -f pvc-postgres.yaml
kubectl apply -f pod-postgres.yaml
kubectl exec -it pod-postgres -- psql -U postgres -c "CREATE TABLE test (id int); INSERT INTO test VALUES (42);"
kubectl delete pod pod-postgres
kubectl apply -f pod-postgres.yaml
kubectl exec -it pod-postgres -- psql -U postgres -c "SELECT * FROM test;"
À retenir
- Un conteneur est éphémère — sans volume, les données meurent avec le Pod
emptyDir= partage temporaire entre conteneurs d’un même PodhostPath= accès au node hôte, à éviter en production- PV/PVC = le pattern standard pour le stockage persistant
- StorageClass = provisionnement dynamique, indispensable à l’échelle
- La reclaim policy détermine ce qui arrive aux données quand le PVC est supprimé
WaitForFirstConsumerévite les problèmes de zones en cluster multi-AZ
➡️ La suite : Dans le prochain chapitre, on aborde les ConfigMaps et Secrets pour externaliser la configuration de tes applications. On continue ! 🚀
🖥️ Pratique sur ton propre serveur
Pour suivre Apprendre Kubernetes en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Contenu réservé aux abonnés
Ce chapitre fait partie de la formation complète. Abonne-toi pour débloquer tous les contenus.
Débloquer pour 29 CHF/moisLe chapitre 1 de chaque formation est gratuit.
Série pas encore débloquée
Termine la série prérequise d'abord pour accéder à ce contenu.
Aller à la série prérequiseSérie : Apprendre Kubernetes
5 / 12- Pourquoi Kubernetes ? L'orchestration expliquée
- Architecture K8s et premières commandes kubectl
- Deployments : déployer et mettre à jour
- Services : exposer tes applications
- 5 Volumes et stockage persistant
- 6 ConfigMaps et Secrets
- 7 RBAC : qui a accès à quoi
- 8 Network Policies et Pod Security
- 9 CNI et networking K8s en détail
- 10 Service Mesh : Istio et Linkerd
- 11 Helm : le package manager de K8s
- 12 Créer et publier son chart Helm
Sur cette page
Articles liés
Pourquoi Kubernetes ? L'orchestration expliquée
Découvre pourquoi Kubernetes est devenu le standard de l'orchestration : architecture, concepts fondamentaux et installation locale.
Architecture K8s et premières commandes kubectl
Installe Kind, lance ton premier déploiement et maîtrise les commandes kubectl essentielles.
Deployments : déployer et mettre à jour
Maîtrise les Deployments Kubernetes : ReplicaSets, rolling updates, rollbacks et scaling horizontal.