CKAD - Volumes et Persistance
🎯 Objectifs
Dans ce module, tu vas :
- ✅ Comprendre les différents types de Volumes
- ✅ Utiliser les Volumes avec tes Pods
- ✅ Maîtriser PersistentVolumes et PersistentVolumeClaims
- ✅ Gérer le cycle de vie des données
- ✅ Déboguer les problèmes de stockage
- ✅ Utiliser les StorageClasses
📋 Prérequis
- Module Kubernetes - Intermédiaire complété
- Module CKAD - Préparation lu
- Module CKAD - Applications complété
📖 Pourquoi ce module ?
Les Volumes et Stockage c'est 15% de la CKAD, mais c'est crucial pour les applications avec données (bases de données, caches, uploads de fichiers).
Tu dois maîtriser :
- Les Volumes simples (emptyDir, hostPath)
- Les Volumes persistants (PV, PVC)
- Comment connecter une app à du stockage
🔧 Types de Volumes
Problème
Les Pods sont éphémères. Quand un Pod supprime, ses données disparaissent. Comment on persiste les données ?
Solution : Volumes
Kubernetes offre plusieurs types de volumes selon tes besoins.
emptyDir : Volume temporaire (défaut)
Un volume vide qui existe pendant la vie du Pod. Parfait pour les fichiers temporaires.
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: temp-data
mountPath: /tmp/data
- name: log-cleaner # Sidecar
image: busybox
volumeMounts:
- name: temp-data
mountPath: /tmp/data
volumes:
- name: temp-data
emptyDir: {}Cas d'usage :
- Fichiers temporaires
- Cache entre conteneurs d'un même Pod
- Logs avant d'être envoyés ailleurs
hostPath : Accès à la machine
Montage un répertoire du Node dans le Pod. Dangereux en production (lie le Pod à un Node spécifique).
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
spec:
containers:
- name: debug
image: busybox
volumeMounts:
- name: host-logs
mountPath: /host/logs
volumes:
- name: host-logs
hostPath:
path: /var/log
type: DirectoryCas d'usage :
- Débugage (accéder aux logs du Node)
- Apps avec accès hardware
- Jamais en production normale
Volumes cloud
Montage du stockage du cloud provider.
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
awsElasticBlockStore:
volumeID: vol-1234567890abcdef0
fsType: ext4Types :
awsElasticBlockStore(AWS EBS)gcePersistentDisk(Google Cloud)azureDisk(Azure)cephfs(Ceph)
💾 PersistentVolume & PersistentVolumeClaim
Problème
Demander directement un volume spécifique (EBS, GCE) couple ton Deployment au cloud provider. Tu veux de l'abstraction.
Solution : PV & PVC
- PersistentVolume (PV) : Ressource de stockage (créée par admin)
- PersistentVolumeClaim (PVC) : Requête pour du stockage (utilisée par développeur)
Workflow
Développeur crée PVC → Kubernetes cherche un PV libre et compatible → Match → Pod utilise la PVCCréer un PersistentVolume
L'admin cluster crée les PV (avec un cloud provider) :
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-1
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce # Accès : un seul Pod en lecture/écriture
persistentVolumeReclaimPolicy: Delete # Supprimer quand la PVC est supprimée
storageClassName: standard
awsElasticBlockStore:
volumeID: vol-1234567890abcdef0
fsType: ext4Créer une PersistentVolumeClaim
Le développeur demande du stockage :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 5GiUtiliser la PVC dans un Pod
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-dataAccess Modes (modes d'accès)
| Mode | Comportement |
|---|---|
ReadWriteOnce (RWO) | Un seul Pod, lecture/écriture |
ReadOnlyMany (ROX) | Plusieurs Pods, lecture seule |
ReadWriteMany (RWX) | Plusieurs Pods, lecture/écriture (NFS, EFS) |
ReadWriteOncePod (RWOP) | Un seul Pod, lecture/écriture (Kubernetes 1.22+) |
Reclaim Policy
| Policy | Comportement |
|---|---|
Delete | Supprimer le volume quand la PVC est supprimée |
Retain | Garder le volume (manuel cleanup) |
Recycle | Vider le volume (deprecated) |
🏭 StorageClass : Provisionner automatiquement
Problème
L'admin doit créer manuellement les PV. Si tu as besoin de 100 volumes, c'est fastidieux.
Solution : StorageClass
Une StorageClass automatise la création de PV.
Créer une StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com # Provisionneur (AWS, GCP, Azure, etc.)
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
reclaimPolicy: Delete
allowVolumeExpansion: trueUtiliser une StorageClass dans une PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd # Référence à la StorageClass
resources:
requests:
storage: 20GiQuand tu créis cette PVC, Kubernetes appelle le provisionneur EBS, qui crée automatiquement un volume EBS et un PV.
StorageClass par défaut
La plupart des clusters ont une StorageClass par défaut. Si tu omets storageClassName, c'est celle-ci qui est utilisée.
# Voir les StorageClasses
k get storageclass
# Voir la default
k get storageclass default -o yaml🗂️ Volumes dans un Deployment
Problème
Comment partager du stockage entre les replicas d'un Deployment ?
Si tu utilises ReadWriteOnce, seul un Pod peut avoir le volume. Les autres répliques ne peuvent pas l'utiliser.
Solution :
- Soit chaque replica a son propre PVC (possible)
- Soit tu utilises un volume
ReadWriteMany(NFS, EFS, AzureFiles) - Soit tu utilises un StatefulSet avec
volumeClaimTemplates
Exemple : Deployment avec ReadWriteOnce
Chaque replica a son propre PVC :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data-1
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data-2
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 2
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
# Note : ça ne marche pas vraiment, chaque replica irait sur la même PVC
# Solution : StatefulSet ou volumes cloud ReadWriteMany
containers:
- name: app
image: app:1.0
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data-1Meilleure solution : StatefulSet avec volumeClaimTemplates
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: app
spec:
serviceName: app
replicas: 3
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: app:1.0
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 5GiKubernetes crée automatiquement :
data-app-0data-app-1data-app-2
Chaque replica a sa propre PVC et son propre stockage.
🔧 Déboguer les problèmes de stockage
PVC en "Pending"
# Voir l'état
k get pvc
k describe pvc app-data
# Output possible :
# Status: Pending
# Events:
# Type Reason Age Message
# ---- ------ ---- -------
# Normal ExternalProvisioning 5s waiting for a volume to be created
# Normal Provisioning 2s Provisioning succeededSolutions :
- Attendre que le provisionneur crée le volume (peut prendre quelques secondes)
- Vérifier que la StorageClass existe
- Vérifier les logs du provisionneur
Pod ne peut pas monter le volume
# Voir l'erreur
k describe pod myapp
# Output possible :
# Volumes:
# data:
# Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim)
# ClaimName: app-data
# ReadOnly: false
# Events:
# Type Reason Message
# ---- ------ -------
# Warning FailedMount MountVolume.MountDevice failed for volume "pv-1"Solutions :
- Vérifier que la PVC existe
- Vérifier les access modes (RWO vs RWX)
- Vérifier que le PV et le Pod sont sur le même Node (si hostPath)
- Vérifier les logs du kubelet du Node
Données perdues après restart
Si tu utilises emptyDir, les données disparaissent. Utilise une PVC à la place.
# Mauvais
volumes:
- name: data
emptyDir: {}
# Bon
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data🔧 Exemple complet : App avec persistance
---
# StorageClass (peut être fourni par le cloud)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: app-storage
provisioner: ebs.csi.aws.com
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: app-storage
resources:
requests:
storage: 20Gi
---
# Deployment avec volume
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
replicas: 1 # Avec RWO, max 1 replica par PVC
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: app:1.0
ports:
- containerPort: 8080
volumeMounts:
- name: data
mountPath: /app/data
- name: cache
mountPath: /tmp/cache
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data
- name: cache
emptyDir: {}
---
# Service
apiVersion: v1
kind: Service
metadata:
name: app
spec:
type: ClusterIP
selector:
app: app
ports:
- port: 80
targetPort: 8080📊 Résumé
| Type | Persistance | Partage | Cas d'usage |
|---|---|---|---|
emptyDir | ❌ Non | Entre conteneurs | Fichiers temp |
hostPath | ✅ Oui | Non | Débugage |
PVC/RWO | ✅ Oui | ❌ Non | Monolithes |
PVC/RWX | ✅ Oui | ✅ Oui | Partage fichiers |
StatefulSet + PVC | ✅ Oui | Chacun son | Bases de données |
🚀 Prochaines Étapes
Tu as maintenant couvert tous les domaines de la CKAD !
- Revois les modules précédents
- Fais des exercices pratiques
- Pratique sur des clusters réels
- Passe l'examen CKAD officiel 🎓