Exercice 04 : Volumes - emptyDir et PersistentVolumeClaims
🎯 Objectifs
À la fin de cet exercice, vous serez capable de :
- ✅ Créer un volume
emptyDirpartagé entre deux conteneurs d'un même pod - ✅ Créer un PVC et l'associer à un Deployment
- ✅ Écrire des données dans un volume persistant et vérifier qu'elles survivent à un redémarrage de pod
- ✅ Distinguer les différents types de volumes et leurs cas d'usage
Durée estimée : 30 minutes
Difficulté : ⭐⭐☆☆☆ (Intermédiaire)
Prérequis : Exercice 01 complété, namespace intermediaire existant
📖 Contexte
Par défaut, les fichiers créés dans un conteneur disparaissent avec lui. Pour une base de données, un cache Redis ou un stockage d'upload de fichiers, il faut de la persistance. Kubernetes propose deux niveaux :
- emptyDir : stockage temporaire partagé entre les conteneurs d'un pod (disparaît avec le pod)
- PersistentVolume (PV) + PVC : stockage persistant qui survit à la mort du pod
📋 Énoncé
Explorez les volumes emptyDir puis créez un stockage persistant avec PVC.
🧭 Déroulement de l'exercice
Tâche 1 : Volume emptyDir - partage entre conteneurs
Un emptyDir est utile pour partager des fichiers entre deux conteneurs dans le même pod (sidecar pattern) : par exemple, un conteneur qui génère des logs et un conteneur qui les traite.
cat > emptydir-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: shared-volume
namespace: intermediaire
spec:
volumes:
- name: data-shared
emptyDir: {} # Volume vide créé quand le pod démarre
containers:
# Conteneur 1 : écrit des données dans le volume
- name: writer
image: busybox:latest
command: ["/bin/sh", "-c"]
args:
- |
while true; do
echo "$(date): message from writer" >> /data/messages.log
sleep 5
done
volumeMounts:
- name: data-shared
mountPath: /data
# Conteneur 2 : lit les données depuis le même volume
- name: reader
image: busybox:latest
command: ["/bin/sh", "-c"]
args:
- |
while true; do
echo "=== Reader sees:"
cat /data/messages.log 2>/dev/null || echo "(vide)"
sleep 10
done
volumeMounts:
- name: data-shared
mountPath: /data # Même chemin de montage
EOF
kubectl apply -f emptydir-pod.yaml
# Suivre les logs du reader
kubectl logs shared-volume -c reader -n intermediaire -f# Écrire depuis le conteneur writer directement
kubectl exec shared-volume -c writer -n intermediaire -- \
sh -c 'echo "message manuel" >> /data/messages.log'
# Vérifier que le reader le voit
kubectl exec shared-volume -c reader -n intermediaire -- \
cat /data/messages.logIndice : Le volume
emptyDirest créé vide au démarrage du pod. Il est partagé entre TOUS les conteneurs du pod. Si le pod est supprimé, les données sont perdues. Si un conteneur redémarre (sans supprimer le pod), les données sont conservées.
Tâche 2 : Créer un PersistentVolumeClaim
cat > pvc.yaml << 'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
namespace: intermediaire
spec:
accessModes:
- ReadWriteOnce # Montable par un seul nœud en lecture/écriture
storageClassName: standard # StorageClass de minikube
resources:
requests:
storage: 1Gi
EOF
kubectl apply -f pvc.yaml
# Voir l'état du PVC : STATUS doit passer de Pending à Bound
kubectl get pvc -n intermediaire -wIndice : Sur minikube, la StorageClass
standardprovisionne automatiquement un volume (provisionnement dynamique). Sur un vrai cluster AWS, on utiliseraitgp2ougp3; sur GKEstandard-rwo. Le PVC passe dePendingàBoundune fois qu'un PersistentVolume lui est associé.
Tâche 3 : Utiliser le PVC dans un Deployment
cat > postgres-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-demo
namespace: intermediaire
spec:
replicas: 1
selector:
matchLabels:
app: postgres-demo
template:
metadata:
labels:
app: postgres-demo
spec:
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: data-pvc # Référencer le PVC créé
containers:
- name: postgres
image: postgres:16-alpine
env:
- name: POSTGRES_PASSWORD
value: "testpassword"
- name: POSTGRES_DB
value: "demo"
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data # Les données sont persistées ici
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
EOF
kubectl apply -f postgres-deployment.yaml
# Attendre que le pod soit Running
kubectl get pods -n intermediaire -l app=postgres-demo -wTâche 4 : Tester la persistance
# Obtenir le nom du pod
POD=$(kubectl get pods -n intermediaire -l app=postgres-demo -o jsonpath='{.items[0].metadata.name}')
# Créer des données dans la base
kubectl exec "$POD" -n intermediaire -- \
psql -U postgres -d demo -c "CREATE TABLE test (id serial PRIMARY KEY, message TEXT);"
kubectl exec "$POD" -n intermediaire -- \
psql -U postgres -d demo -c "INSERT INTO test (message) VALUES ('Données persistées !');"
kubectl exec "$POD" -n intermediaire -- \
psql -U postgres -d demo -c "SELECT * FROM test;"
# Supprimer le pod (le Deployment en crée un nouveau)
kubectl delete pod "$POD" -n intermediaire
# Attendre le nouveau pod
kubectl get pods -n intermediaire -l app=postgres-demo -w
# Vérifier que les données sont toujours là !
NEW_POD=$(kubectl get pods -n intermediaire -l app=postgres-demo -o jsonpath='{.items[0].metadata.name}')
kubectl exec "$NEW_POD" -n intermediaire -- \
psql -U postgres -d demo -c "SELECT * FROM test;"Vérification : La table et les données sont présentes dans le nouveau pod. Le volume (PVC) survit à la mort du pod.
✅ Vérification du résultat
- Le volume
emptyDirest bien partagé entre les deux conteneurs du pod kubectl get pvc -n intermediaireaffiche le PVC en étatBound- Les données PostgreSQL survivent à la suppression et recréation du pod
kubectl get pvliste le PersistentVolume auto-créé par minikube
💡 À retenir
| Type | Survit à la mort du pod ? | Cas d'usage |
|---|---|---|
| emptyDir | ❌ Non | Sidecar, fichiers temporaires, cache |
| hostPath | ✅ Oui (si même nœud) | Dev seulement (déconseillé en prod) |
| PVC | ✅ Oui | Bases de données, fichiers utilisateurs |
Relation PVC / PV :
PVC (demande de stockage) ← lie → PV (stockage réel)
↑ provisionné automatiquement par StorageClass✨ Solution Complète
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mon-pvc
spec:
accessModes: [ReadWriteOnce]
storageClassName: standard
resources:
requests:
storage: 5Gi
# Dans le Deployment
volumes:
- name: mon-volume
persistentVolumeClaim:
claimName: mon-pvc
containers:
- volumeMounts:
- name: mon-volume
mountPath: /data