CKA - Domaine 5 : Stockage et Volumes Persistants (10%)
🎯 Objectifs
À la fin de ce module, tu seras capable de :
- ✅ Expliquer la différence entre volumes éphémères et persistants
- ✅ Créer et utiliser des PersistentVolumes et PersistentVolumeClaims
- ✅ Comprendre les modes d'accès et les politiques de récupération
- ✅ Utiliser des StorageClasses pour le provisionnement dynamique
- ✅ Monter des volumes dans des Pods (ConfigMap, Secret, emptyDir, hostPath)
- ✅ Configurer des StatefulSets avec des volumes persistants par pod
📋 Prérequis
- Module CKA : Services et Réseau lu
- Comprendre les pods et les StatefulSets (CKA : Workloads)
📦 Les types de volumes
Volumes éphémères (disparaissent avec le Pod)
spec:
volumes:
# emptyDir : vide au démarrage, partagé entre les conteneurs du Pod
- name: cache
emptyDir: {}
# emptyDir en mémoire (tmpfs)
- name: cache-mem
emptyDir:
medium: Memory
sizeLimit: 256Mi
# ConfigMap monté comme fichiers
- name: config-files
configMap:
name: app-config
# Secret monté comme fichiers
- name: secret-files
secret:
secretName: db-creds
defaultMode: 0400 # permissions sur les fichiers
# hostPath : un chemin sur le node (déconseillé en prod)
- name: host-data
hostPath:
path: /var/log
type: Directory # Directory, File, DirectoryOrCreate, FileOrCreatespec:
containers:
- name: app
volumeMounts:
- name: cache
mountPath: /tmp/cache
- name: config-files
mountPath: /etc/app
readOnly: true
- name: secret-files
mountPath: /etc/secrets
readOnly: truePartager des données entre conteneurs d'un même Pod
# Deux conteneurs partagent le même volume emptyDir
spec:
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: writer
image: busybox
command: ["sh", "-c", "while true; do date >> /data/output.txt; sleep 5; done"]
volumeMounts:
- name: shared-data
mountPath: /data
- name: reader
image: busybox
command: ["sh", "-c", "tail -f /data/output.txt"]
volumeMounts:
- name: shared-data
mountPath: /data🗄️ PersistentVolumes (PV)
Un PersistentVolume est une ressource de stockage provisionnée dans le cluster, indépendante du cycle de vie des Pods.
Créer un PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-local
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce # un seul node peut lire/écrire
persistentVolumeReclaimPolicy: Retain # que faire après que le PVC est supprimé
storageClassName: manual # correspond au storageClassName du PVC
hostPath: # type de stockage (hostPath pour les tests)
path: /mnt/dataModes d'accès
| Mode | Abréviation | Description |
|---|---|---|
ReadWriteOnce | RWO | Lu/écrit par un seul node à la fois |
ReadOnlyMany | ROX | Lu par plusieurs nodes simultanément |
ReadWriteMany | RWX | Lu/écrit par plusieurs nodes simultanément |
ReadWriteOncePod | RWOP | Lu/écrit par un seul Pod (v1.22+) |
💡
hostPathne supporte queReadWriteOnce. Pour du RWX, il faut NFS ou un système de fichiers distribué.
Politiques de récupération (reclaimPolicy)
| Politique | Comportement après suppression du PVC |
|---|---|
Retain | Le PV reste, les données sont conservées, doit être libéré manuellement |
Delete | Le PV et le stockage sous-jacent sont supprimés |
Recycle | (déprécié) Efface les données et rend le PV disponible |
📋 PersistentVolumeClaims (PVC)
Un PVC est une demande de stockage faite par un utilisateur. Kubernetes lie automatiquement le PVC à un PV compatible.
Créer un PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-app
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual # doit correspondre au PV
resources:
requests:
storage: 1Gi # taille demandée (≤ capacité du PV)# Vérifier que le PVC est lié à un PV
kubectl get pvc
# STATUS doit être "Bound"
kubectl get pv
# CLAIM doit montrer "default/pvc-app"Utiliser un PVC dans un Pod
spec:
volumes:
- name: app-storage
persistentVolumeClaim:
claimName: pvc-app # nom du PVC
containers:
- name: app
image: nginx
volumeMounts:
- name: app-storage
mountPath: /usr/share/nginx/htmlCycle de vie PV / PVC
PV créé (Available)
↓
PVC créé → Kubernetes lie PVC au PV (Bound)
↓
Pod utilise le PVC
↓
PVC supprimé
↓
PV passe en Released (données encore là si reclaimPolicy: Retain)🏭 StorageClass et provisionnement dynamique
Le problème du provisionnement statique
Créer un PV manuellement pour chaque application est fastidieux. Les StorageClasses permettent de créer des PVs automatiquement quand un PVC est créé.
Voir les StorageClasses disponibles
kubectl get storageclass
kubectl get sc # raccourciPVC avec provisionnement dynamique
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-dynamic
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard # nom de la StorageClass
resources:
requests:
storage: 2Gi
# Pas besoin de créer un PV manuellement : il sera créé automatiquementCréer une StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/no-provisioner # provisioner local (pour les tests)
volumeBindingMode: WaitForFirstConsumer # ne lie qu'au moment où un pod utilise le PVC
reclaimPolicy: DeleteStorageClass par défaut
# Voir quelle StorageClass est utilisée par défaut
kubectl get sc | grep default
# Un PVC sans storageClassName utilise la SC par défaut
kubectl annotate sc <nom> storageclass.kubernetes.io/is-default-class=true🗄️ StatefulSet avec VolumeClaimTemplates
La force des StatefulSets : chaque pod reçoit son propre PVC automatiquement.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres"
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
env:
- name: POSTGRES_PASSWORD
value: "password"
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates: # un PVC par pod
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 1GiRésultat :
- Pod
postgres-0→ PVCdata-postgres-0 - Pod
postgres-1→ PVCdata-postgres-1 - Pod
postgres-2→ PVCdata-postgres-2
kubectl get pvc | grep postgres
kubectl get pv🔧 Expansion de volumes
# Voir si la StorageClass supporte l'expansion
kubectl get sc <nom> -o yaml | grep allowVolumeExpansion
# Agrandir un PVC (éditer la taille)
kubectl edit pvc pvc-app
# Modifier resources.requests.storage vers la nouvelle taille
# Le PV est redimensionné automatiquement (si supporté)
kubectl get pvc pvc-app # STATUS passe en "FilesystemResizePending" puis "Bound"📊 Récapitulatif des commandes clés
# PV et PVC
kubectl get pv # liste tous les PVs du cluster
kubectl get pvc -A # liste tous les PVCs de tous les namespaces
kubectl describe pvc <name> -n <namespace> # détails du PVC et du PV lié
# StorageClass
kubectl get sc # liste les StorageClasses
kubectl describe sc <name> # voir le provisioner et la reclaimPolicy
# Déboguer
kubectl describe pvc <name> # Events : peut montrer "no matching PV found"
kubectl describe pv <name> # voir CLAIM et STATUSVérifier la liaison PV ↔ PVC
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS
# pvc-app Bound pv-local 5Gi RWO manual
kubectl get pv
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
# pv-local 5Gi RWO Retain Bound default/pvc-app🚀 Prochaines Étapes
- Domaine suivant : CKA : Troubleshooting
- Entraîne-toi : crée un PV hostPath, lie-le à un PVC, monte-le dans un Pod, vérifie que les données persistent après suppression du Pod
- Référence : kubernetes.io/docs/concepts/storage/