Aller au contenu

Module 4b · Stockage persistant

Objectifs

  • Comprendre la différence éphémère vs persistant dans Kubernetes.
  • Manipuler PV, PVC et StorageClass - et voir comme c'est lié.
  • Monter un volume dans un pod et prouver que la donnée survit au redémarrage.
  • Durée : ~1 h 15 · Pré-requis : Module 4t - Diagnostiquer.

Le problème : un pod est jetable

Par défaut, le système de fichiers d'un conteneur disparaît quand le pod est recréé. Pour une base de données, un upload, un cache durable… il faut du stockage persistant, découplé du cycle de vie du pod.

graph LR
    P[Pod] -->|monte| PVC[PersistentVolumeClaim]
    PVC -->|lié à| PV[PersistentVolume]
    SC[StorageClass] -->|provisionne dynamiquement| PV

Les trois objets

Objet Rôle
StorageClass Comment provisionner du stockage (le « type » de disque)
PersistentVolume (PV) Un morceau de stockage réel, dans le cluster
PersistentVolumeClaim (PVC) Une demande de stockage par l'app

En pratique : l'app crée un PVC → la StorageClass provisionne dynamiquement un PV → le pod monte le PVC.

kubectl get storageclass     # k9s : :sc
kubectl get pv               # k9s : :pv
kubectl get pvc              # k9s : :pvc

Dans ta sandbox

Le vcluster expose une StorageClass par défaut (souvent local-path). Vérifie avec kubectl get sc : celle marquée (default) est utilisée si un PVC ne précise rien.

Réclamer du stockage - un PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: donnees
spec:
  accessModes: ["ReadWriteOnce"]   # monté en R/W par un seul nœud à la fois
  resources:
    requests:
      storage: 1Gi
kubectl apply -f pvc.yaml
kubectl get pvc donnees       # STATUS doit passer à "Bound"

Access modes

  • ReadWriteOnce (RWO) : un nœud en lecture/écriture (cas le plus courant).
  • ReadOnlyMany (ROX) / ReadWriteMany (RWX) : plusieurs nœuds (besoin d'un backend qui le supporte, ex. NFS).

Monter le PVC dans un pod

apiVersion: v1
kind: Pod
metadata:
  name: ecrivain
spec:
  containers:
    - name: app
      image: busybox
      command: ["sh", "-c", "echo coucou >> /data/journal.txt && sleep 3600"]
      volumeMounts:
        - name: vol
          mountPath: /data
  volumes:
    - name: vol
      persistentVolumeClaim:
        claimName: donnees

StatefulSet (pour les apps à état)

Un Deployment est fait pour des pods interchangeables. Une base de données a besoin d'une identité stable et d'un volume dédié par réplica : c'est le rôle du StatefulSet, via son volumeClaimTemplates (un PVC créé automatiquement par pod). Ses pods ont des noms fixes et ordonnés : db-0, db-1, db-2.

Son compagnon naturel : le Service headless (clusterIP: None) - pas d'IP virtuelle, mais un nom DNS par pod (db-0.db, db-1.db…). Indispensable quand les réplicas ne sont pas interchangeables : on veut parler à db-0 (le primaire), pas à « n'importe qui » - le cas type des bases répliquées (PostgreSQL, MongoDB…).

graph TB
    STS[StatefulSet db] --> P0[db-0]
    STS --> P1[db-1]
    P0 -->|volumeClaimTemplates| V0[(PVC db-0)]
    P1 -->|volumeClaimTemplates| V1[(PVC db-1)]
    H[Service headless<br/>clusterIP: None] -.db-0.db.-> P0
    H -.db-1.db.-> P1

Contraste avec le Deployment de la carte d'assemblage : là, les pods étaient interchangeables (un seul Service, sélection par labels). Ici chaque réplica a son identité fixe, son propre volume et son propre nom DNS - on peut viser db-0 précisément.

:sts        # vue StatefulSets dans k9s

Pratique

Le TP de ce module, dans le terminal de ta sandbox - une fois la lecture faite :

tp start 03b-stockage   # PVC Bound, écrire dans le volume, prouver que la donnée survit au pod
tp start ancrage-4b     # en autonomie ensuite : chaîne PVC → Deployment → Service complète

fais la manip puis tp check (ou tp watch pour l'auto-validation) · tp hint / tp solution si tu bloques.

En séance, on observe d'abord l'anatomie du stockage ensemble (en partage d'écran) ; le TP te fait ensuite prouver que la donnée survit, corrigé. En autonomie : déroule l'observation, puis enchaîne le TP.

Exercice 4b.1 - L'anatomie du stockage (on l'observe ensemble)

Comment une demande de volume devient un disque réel :

  1. Crée le PVC (manifeste ci-dessus) puis kubectl get pvc,pv : le PVC passe Bound, un PV apparaît en face.
  2. kubectl describe pvc : repère sa StorageClass et sa capacité.
  3. kubectl get storageclass : c'est elle qui fabrique le PV à la demande (provisioning dynamique).

On regarde la mécanique ; prouver que la donnée survit au pod supprimé, c'est le TP 03b-stockage qui te le fait vivre.

Exercice 4b.2 - Plein le disque

  1. Crée un PVC de 100Mi.
  2. Dans le pod, dd if=/dev/zero of=/data/gros bs=1M count=200 (dépasse la demande).
  3. Observe : selon le backend, l'écriture échoue ou non - discute la différence entre demande (request) et limite réelle du backend de stockage.

Ce qu'il faut retenir

  • PVC = demande, PV = disque réel, StorageClass = comment le fabriquer.
  • Une StorageClass par défaut permet le provisioning dynamique (pas de PV à créer à la main).
  • Supprimer le pod ne supprime pas la donnée ; supprimer le PVC (selon la reclaimPolicy) si.
  • Apps à état → StatefulSet + volumeClaimTemplates (+ Service headless : un DNS par pod).

Quiz éclair

Teste-toi : réponds de tête, puis déplie.

1. PVC, PV, StorageClass : qui est quoi ?

PVC = la demande de stockage (par l'app), PV = le disque réel, StorageClass = comment le fabriquer (provisioning dynamique).

2. Tu supprimes le pod. La donnée est-elle perdue ?

Non : le PVC/PV survit au pod. C'est en supprimant le PVC que la donnée peut partir (selon la reclaimPolicy du PV).

3. Quel objet pour une base de données (identité + volume stables) ?

Un StatefulSet avec volumeClaimTemplates (un PVC dédié créé par réplica).

➡️ Suite : Module 4c - Observabilité