Aller au contenu
Volumes et stockage persistant

Volumes et stockage persistant

200 Pratiquer ⏱ 1 h 20 kuberneteskubectlkindpostgresqlcsi

À la fin, vous saurez

  • Expliquer pourquoi les données écrites dans un conteneur disparaissent, et choisir entre volume éphémère et volume persistant
  • Décrire le rôle du PersistentVolume, du PersistentVolumeClaim et de la StorageClass dans le provisionnement dynamique
  • Choisir un mode d'accès et un mode de liaison adaptés à un stockage bloc zonal
  • Éviter la perte de données liée à la politique de récupération Delete
  • Déployer une base PostgreSQL de formation sur un volume persistant, et dire pourquoi ce n'est pas une solution de production
  • Diagnostiquer un PersistentVolumeClaim Pending et un volume bloqué sur un autre nœud

Prérequis

Testé avec kubectl 1.36.0 kubernetes 1.36 , vérifié le 5 octobre 2026

Pourquoi

Signalements a besoin d'une base PostgreSQL. En production, ce sera une base managée, hors du cluster (Scaleway en pratique, leçon 3). Mais pour se former, et pour comprendre ce que Kubernetes sait faire du stockage, on va en faire tourner une dans le cluster formation.

Premier essai, naïf : un Deployment avec l'image postgres:18, sans rien d'autre. La base démarre, Signalements s'y connecte, on crée quelques signalements. Puis on fait kubectl delete pod sur le pod de la base, comme on le ferait pour le redémarrer. Le Deployment en recrée un aussitôt, la base répond de nouveau... vide. Tous les signalements ont disparu.

Rien n'a dysfonctionné. Le conteneur écrivait dans sa propre couche d'écriture, comme le cours Docker : les fondamentaux l'a montré : cette couche appartient au conteneur et disparaît avec lui. Un pod est jetable par conception, puisque Kubernetes le remplace à la moindre occasion (mise à jour, nœud perdu, éviction). Une application qui garde un état doit donc le ranger hors du pod, dans un stockage dont la vie est indépendante de celle des pods. Cette leçon montre comment Kubernetes fournit ce stockage, et ce qui reste fragile.

Les concepts

Les volumes éphémères

Un volume, dans Kubernetes, est un répertoire accessible aux conteneurs d'un pod, déclaré dans spec.volumes et monté par volumeMounts. Certains volumes vivent exactement aussi longtemps que le pod :

  • emptyDir : un répertoire vide créé à la naissance du pod, sur le disque du nœud, et supprimé à sa disparition. Il survit au redémarrage d'un conteneur (après un OOMKilled, par exemple) mais pas au remplacement du pod. Usages : un cache, un espace de travail temporaire, un fichier partagé entre deux conteneurs du même pod. Un champ sizeLimit borne sa taille ; au-delà, le kubelet évince le pod.
  • emptyDir avec medium: Memory : le même, dans un tmpfs, en mémoire. Très rapide, mais la documentation prévient que les fichiers écrits comptent dans la limite de mémoire du conteneur qui les écrit : un cache en mémoire mal borné mène à l'OOMKilled.
  • configMap, secret, projected : les fichiers d'une ConfigMap ou d'un Secret (leçon 7), ou de plusieurs sources réunies dans un même répertoire (projected), y compris le jeton de compte de service du pod.

Aucun de ces volumes ne convient à une base de données.

PersistentVolume, PersistentVolumeClaim, StorageClass

Pour un stockage qui survit aux pods, Kubernetes sépare trois rôles, en trois objets :

  • Un PersistentVolume (PV) représente un morceau de stockage réel : un volume bloc chez le fournisseur, un partage NFS, un répertoire d'un nœud. C'est un objet du cluster, sans namespace, avec une capacité, des modes d'accès et une politique de récupération.
  • Un PersistentVolumeClaim (PVC) est une demande de stockage faite par une application, dans son namespace : « il me faut 5 Gio, en lecture-écriture par un nœud ». Le pod ne connaît que le PVC.
  • Une StorageClass décrit une catégorie de stockage que le cluster sait fabriquer : quel pilote, quels paramètres (performances, chiffrement), quelle politique de récupération, quel mode de liaison.

Le cycle ordinaire est le provisionnement dynamique : l'application crée un PVC qui nomme une StorageClass (ou s'appuie sur la classe par défaut) ; un contrôleur voit la demande, demande au pilote de créer le volume chez le fournisseur, crée le PV correspondant, et le lie (bind) au PVC. La liaison est exclusive et bijective : un PV n'est lié qu'à un PVC, et réciproquement. Quand un pod qui utilise le PVC est placé sur un nœud, le volume y est attaché (comme un disque branché à la machine), formaté au besoin, puis monté dans le conteneur.

    flowchart LR
  P["Pod<br/>volumes: claimName"] --> C["PersistentVolumeClaim<br/>5Gi, RWO, classe"]
  C -->|"liaison"| V["PersistentVolume"]
  S["StorageClass<br/>pilote, paramètres"] -.->|"provisionnement<br/>dynamique"| V
  V --> D["Volume réel<br/>(bloc Scaleway, répertoire local...)"]
  

Cette séparation permet à l'équipe qui écrit l'application de ne rien savoir du fournisseur : le même PVC fonctionne sur kind et sur Kapsule, seule la StorageClass diffère.

CSI : les pilotes de stockage

Les pilotes de stockage ne font plus partie du code de Kubernetes. Ils suivent la Container Storage Interface (CSI), une spécification commune à plusieurs orchestrateurs : le fournisseur publie un pilote qui sait créer, attacher, monter, agrandir et photographier ses volumes, et Kubernetes l'appelle par cette interface. Le pilote de Scaleway (csi.scaleway.com) est installé par défaut sur chaque cluster Kapsule et gère les volumes Block Storage ; un second pilote gère File Storage.

Les modes d'accès

Un PVC déclare comment le volume sera utilisé :

ModeAbréviationSignification
ReadWriteOnceRWOLecture-écriture par un seul nœud à la fois. Plusieurs pods du même nœud peuvent encore y accéder
ReadWriteOncePodRWOPLecture-écriture par un seul pod dans tout le cluster (stable depuis 1.29, pilotes CSI seulement)
ReadOnlyManyROXLecture seule par plusieurs nœuds
ReadWriteManyRWXLecture-écriture par plusieurs nœuds

Le mode d'accès dépend de ce que le stockage sait faire, pas de ce que l'on souhaite. Un disque bloc ne s'attache qu'à une machine à la fois : c'est du RWO, ou du RWOP. Le code du pilote de Scaleway le confirme : il n'accepte que des modes « un seul nœud ». Pour du RWX, il faut un système de fichiers partagé, comme File Storage chez Scaleway (classe sfs-standard, qui demande d'activer son pilote sur le cluster par l'étiquette scw-filestorage-csi et des nœuds POP2, d'après la documentation au 5 octobre 2026), ou un NFS.

Une précision qui surprend : RWO interdit deux nœuds, pas deux pods. Deux pods placés sur le même nœud peuvent monter le même volume RWO et écrire en même temps. Pour une base de données, c'est la corruption assurée : RWOP l'empêche.

Le stockage bloc est zonal

Un volume Block Storage existe dans une zone (cours Le cloud : les fondamentaux, leçon 5), et ne s'attache qu'à une instance de la même zone. Le pilote de Scaleway l'annonce à Kubernetes par une topologie : chaque volume porte l'information de sa zone, et chaque nœud la sienne. La documentation de Scaleway est explicite : sur un cluster Kapsule réparti sur plusieurs zones, les volumes persistants restent limités à leur zone.

Deux conséquences :

  • Quand créer le volume ? Si le volume est créé dès la création du PVC (mode de liaison Immediate, la valeur par défaut d'une StorageClass), il l'est dans une zone choisie sans savoir où ira le pod. Le pod, contraint par ailleurs (ressources, affinités), peut se retrouver obligé d'aller dans une zone où il n'a pas de place. Le mode WaitForFirstConsumer retarde la création du volume jusqu'à ce qu'un pod qui l'utilise soit placé, et crée le volume dans la zone de ce pod.
  • Le pod est ensuite attaché à sa zone. Si tous les nœuds de cette zone disparaissent, le pod ne peut pas être recréé ailleurs : son volume n'y est pas. Pour survivre à la perte d'une zone, l'application doit répliquer ses données elle-même, entre volumes de zones différentes (ce que fait une base de données répliquée), ou confier ses données à un service régional.

La politique de récupération

Que devient le volume réel quand on supprime le PVC ? La StorageClass (et après elle, chaque PV) porte une politique de récupération (reclaim policy) :

  • Delete : le PV et le volume chez le fournisseur sont supprimés. C'est la valeur par défaut des StorageClass, et celle des classes de Scaleway et de kind.
  • Retain : le PV passe en état Released, et le volume réel est conservé. Il faut un humain pour le récupérer (le relier à un nouveau PVC) ou le supprimer.

Avec Delete, un kubectl delete pvc, un kubectl delete namespace ou un outil de déploiement qui supprime ce qu'il ne voit plus dans Git (l'élagage du cours GitOps avec Argo CD) détruit les données, sans corbeille. Kubernetes protège un PVC encore utilisé par un pod (sa suppression attend la fin du pod), pas un PVC inutilisé.

Agrandir et photographier

  • Agrandir : si la StorageClass porte allowVolumeExpansion: true, il suffit d'augmenter spec.resources.requests.storage du PVC. Le pilote agrandit le volume, puis le système de fichiers. Le pilote de Scaleway le fait à chaud, sans détacher le volume. On ne peut jamais réduire un PVC.
  • Photographier : un VolumeSnapshot demande au pilote CSI un instantané d'un PVC, et un nouveau PVC peut être créé à partir de cet instantané (champ dataSource). Ces objets ne sont pas dans le cœur de Kubernetes : ce sont des ressources personnalisées, et leur contrôleur doit être installé par la distribution. Le pilote de Scaleway prend en charge les instantanés ; vérifiez sur votre cluster qu'une VolumeSnapshotClass existe (kubectl get volumesnapshotclass). Un instantané d'un disque de base de données en marche est cohérent après plantage seulement (cours Le cloud : les fondamentaux, leçon 5).

En pratique

Les manifestes de cette leçon ont été validés syntaxiquement ; les commandes sur le cluster décrivent ce que vous devez observer, sans sortie inventée.

Ce que fournit votre cluster

$ kubectl get storageclass
$ kubectl get storageclass standard -o yaml

Sur kind, une seule classe, standard, marquée par défaut. Le code de kind la définit ainsi : pilote rancher.io/local-path (le local-path-provisioner), politique Delete, mode WaitForFirstConsumer. Ce pilote crée simplement un répertoire sous /var/local-path-provisioner dans le nœud qui accueille le pod. C'est parfait pour se former, et c'est la preuve qu'un PV n'est qu'une abstraction : les données d'un cluster kind vivent dans les conteneurs qui jouent les nœuds, et disparaissent avec kind delete cluster.

Sur Kapsule, la même commande liste les classes du pilote csi.scaleway.com. La documentation et le dépôt du pilote citent sbs-default, et des classes préconfigurées sbs-5k et sbs-15k pour deux niveaux de performances ; d'anciens clusters ou d'anciennes pages de documentation montrent aussi scw-bssd. Lisez le YAML de la classe par défaut : son reclaimPolicy, son volumeBindingMode et son allowVolumeExpansion décident de ce qui suit.

Le Secret de la base

La base a besoin d'un mot de passe, rangé dans un Secret (leçon 7) et créé sans passer par la ligne de commande :

$ printf '%s' "$(openssl rand -base64 24)" > mdp-postgres.txt
$ kubectl create secret generic postgres -n signalements \
    --from-file=POSTGRES_PASSWORD=mdp-postgres.txt
$ rm mdp-postgres.txt

Il vous faudra ce mot de passe pour construire le Secret signalements-db de la leçon 7 : relisez-le avec kubectl get secret postgres -n signalements -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d, puis recréez signalements-db avec la bonne URL.

Le PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-donnees
  namespace: signalements
spec:
  accessModes:
    - ReadWriteOncePod
  resources:
    requests:
      storage: 5Gi
  • ReadWriteOncePod : un seul pod à la fois dans tout le cluster, ce qui protège la base d'un second processus PostgreSQL qui écrirait dans les mêmes fichiers. La documentation ne le garantit que pour les volumes CSI : le pilote de Scaleway l'accepte ; le local-path-provisioner de kind, qui n'est pas un pilote CSI, accepte de créer le volume, mais la garantie d'exclusivité n'y est pas promise. Si votre pilote le refuse, ReadWriteOnce.
  • Pas de storageClassName : la classe par défaut du cluster est utilisée. En production, nommez-la explicitement : un changement de classe par défaut ne doit pas changer votre application.
$ kubectl apply -f pvc.yaml
$ kubectl get pvc -n signalements
$ kubectl describe pvc postgres-donnees -n signalements

Le PVC reste Pending, et c'est normal : avec WaitForFirstConsumer, aucun volume n'est créé tant qu'aucun pod ne l'utilise. Les événements de kubectl describe le disent, avec le message du contrôleur de volumes : waiting for first consumer to be created before binding.

La base

apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: signalements
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:18
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_USER
              value: signalements
            - name: POSTGRES_DB
              value: signalements
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres
                  key: POSTGRES_PASSWORD
          volumeMounts:
            - name: donnees
              mountPath: /var/lib/postgresql
          resources:
            requests: {cpu: 100m, memory: 256Mi}
            limits: {memory: 256Mi}
      volumes:
        - name: donnees
          persistentVolumeClaim:
            claimName: postgres-donnees
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: signalements
spec:
  selector:
    app: postgres
  ports:
    - port: 5432

Trois choix méritent une explication :

  • strategy: type: Recreate. La stratégie par défaut d'un Deployment, RollingUpdate (leçon 5), crée le nouveau pod avant d'arrêter l'ancien. Avec un volume RWOP ou RWO, le nouveau pod ne peut pas monter un volume que l'ancien utilise encore : il attend, l'ancien n'est pas arrêté puisque le nouveau n'est pas prêt, et la mise à jour reste bloquée. Recreate arrête l'ancien d'abord : une courte interruption, mais pas de blocage, et jamais deux PostgreSQL sur les mêmes fichiers.
  • Le point de montage /var/lib/postgresql. Depuis la version 18, l'image officielle range ses données dans un sous-répertoire propre à la version majeure (/var/lib/postgresql/18/docker), et sa documentation demande de monter le volume sur /var/lib/postgresql. Monter le volume plus bas, à l'ancien emplacement, ferait écrire les données hors du volume. Le sous-répertoire évite au passage un piège ancien : un volume formaté en ext4 contient à sa racine un répertoire lost+found, et initdb refuse d'initialiser un répertoire qui n'est pas vide.
  • Le Service postgres : Signalements se connecte à postgres:5432 par son nom (leçon 6).
$ kubectl apply -f postgres.yaml
$ kubectl get pvc,pv -n signalements
$ kubectl get pods -n signalements -l app=postgres -o wide

Le PVC passe en Bound, un PV au nom généré (pvc-...) apparaît, avec sa capacité, son mode d'accès, sa politique Delete et sa classe. Le pod passe en Running une fois PostgreSQL initialisé.

L'épreuve

Faites créer quelques signalements par l'API, puis supprimez le pod de la base :

$ kubectl delete pod -n signalements -l app=postgres
$ kubectl get pods -n signalements -l app=postgres --watch

Le Deployment recrée un pod, qui monte le même volume : les signalements sont toujours là. Sur kind, regardez aussi kubectl describe pv : le PV porte une affinité de nœud (Node Affinity), puisque son répertoire n'existe que sur un nœud. Le nouveau pod est forcément placé sur ce nœud. C'est la version locale de la contrainte de zone de Kapsule.

Agrandir le volume

Si la classe le permet (allowVolumeExpansion: true) :

$ kubectl patch pvc postgres-donnees -n signalements \
    -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
$ kubectl describe pvc postgres-donnees -n signalements

Les événements et les conditions du PVC montrent l'agrandissement du volume, puis celui du système de fichiers ; la capacité affichée passe à 10 Gio. Sur une classe qui ne le permet pas, le serveur d'API refuse la modification. Le local-path-provisioner de kind n'a pas de taille réelle à agrandir : sur kind, cette étape ne s'observe pas vraiment.

Ce que la politique Delete veut dire

Sur kind, et seulement sur kind :

$ kubectl delete deployment postgres -n signalements
$ kubectl delete pvc postgres-donnees -n signalements
$ kubectl get pv

Le PV a disparu, et avec lui le répertoire du nœud : les données sont perdues, sans confirmation. Sur Kapsule, la même séquence supprime le volume Block Storage. Recréez la base si vous voulez poursuivre.

Pour un volume de données qui compte, passez la politique du PV à Retain avant toute manipulation risquée :

$ kubectl patch pv <nom-du-pv> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'

Sous le capot

Les contrôleurs en jeu. Le provisionnement dynamique fait travailler plusieurs composants : le contrôleur de volumes persistants du plan de contrôle surveille les PVC ; pour un pilote CSI, un conteneur auxiliaire du pilote, l'external-provisioner, appelle la méthode CreateVolume du pilote, qui crée le volume par l'API du fournisseur ; le contrôleur d'attachement crée un objet VolumeAttachment, qu'un autre auxiliaire, l'external-attacher, traduit en ControllerPublishVolume (attacher le disque à l'instance) ; enfin le kubelet du nœud appelle le pilote local pour formater et monter le volume (NodeStageVolume, NodePublishVolume). La spécification CSI définit ces appels, et leur découpage explique les états intermédiaires que l'on observe.

La topologie. Le pilote de Scaleway annonce, pour chaque nœud et chaque volume, une clé de topologie topology.csi.scaleway.com/zone. Le planificateur la combine avec les autres contraintes du pod ; avec WaitForFirstConsumer, il choisit d'abord le nœud, et le provisionneur crée le volume dans la zone de ce nœud.

Le volume bloqué sur l'ancien nœud. Quand un pod qui utilise un volume RWO est recréé sur un autre nœud alors que le volume est encore attaché au premier (le nœud a disparu brutalement, ou l'ancien pod n'est pas terminé), le contrôleur d'attachement refuse le second attachement. Les événements du nouveau pod portent la raison FailedAttachVolume. Depuis Kubernetes 1.35, le message commence par Waiting for detach et cite les pods qui retiennent le volume ; les versions antérieures écrivaient Multi-Attach error, que l'on trouve encore dans beaucoup d'articles. Le volume se libère quand l'ancien pod est terminé et le volume détaché ; pour un nœud mort, cela peut demander de supprimer le nœud de l'API ou d'attendre les délais du contrôleur.

Pièges courants

Un PVC Pending qui n'attend rien. Avec WaitForFirstConsumer, c'est normal tant qu'aucun pod n'est placé. Sinon, lisez les événements : no persistent volumes available for this claim and no storage class is set (pas de classe par défaut, ni de classe nommée), ProvisioningFailed (le pilote a échoué : quota, zone, droits de son identité IAM), ou une classe qui n'existe pas.

Un Deployment RollingUpdate sur un volume RWO. La mise à jour reste bloquée, le nouveau pod en ContainerCreating. Recreate, ou un StatefulSet (leçon 10).

Plusieurs réplicas sur un PVC RWO. Le premier pod démarre, les autres restent bloqués sur un autre nœud, ou pire, démarrent sur le même nœud et écrivent tous dans les mêmes fichiers. Une base de données se réplique par ses propres moyens, pas en partageant un disque.

Le namespace supprimé. kubectl delete namespace signalements supprime les PVC, donc, avec Delete, les volumes et les données.

Un montage au mauvais endroit. Les données s'écrivent dans la couche du conteneur au lieu du volume, et l'on ne s'en aperçoit qu'à la première suppression du pod. Vérifiez avec kubectl exec ... -- df -h /var/lib/postgresql que le point de montage est bien le volume.

Le pod qui ne change pas de zone. Sur un cluster multi-zones, un pod lié à un volume ne peut pas être replacé dans une autre zone. Une zone perdue, c'est une base indisponible.

Sécurité

  • Les données au repos : un volume Block Storage n'est pas chiffré par Kubernetes. Le pilote de Scaleway sait chiffrer les volumes avec LUKS, par une StorageClass dédiée et une phrase secrète rangée dans un Secret ; le modèle de responsabilité partagée de Kapsule, dans sa partie consacrée aux données de santé, place ce chiffrement et la gestion de sa clé de votre côté.
  • Qui peut créer un PVC peut consommer du stockage facturé : un ResourceQuota (leçon 8) limite le nombre de PVC et la capacité demandée par namespace (persistentvolumeclaims, requests.storage).
  • Le répertoire d'un nœud (hostPath) donne accès au système de fichiers de la machine : à proscrire pour les applications, il permet de lire les secrets et les données des autres pods. Le local-path-provisioner de kind repose sur ce principe, réservé à un cluster de formation.
  • Les instantanés et les PV Retain contiennent les données : ils se suppriment quand on n'en a plus besoin, et leur accès se contrôle comme celui des volumes.

En production

  • Une base de données dans le cluster est une décision lourde. Il faut gérer la réplication entre zones, les sauvegardes (logiques et instantanés), les mises à jour, la restauration testée. Un opérateur spécialisé (CloudNativePG, par exemple) l'automatise en grande partie. Pour Signalements, Lyneko utilise PostgreSQL managé, hors du cluster (Scaleway en pratique, leçon 3) : le cluster reste sans état, et se reconstruit en quelques minutes.
  • Nommez la StorageClass dans chaque PVC, et choisissez-la pour ses performances (sbs-5k ou sbs-15k chez Scaleway) et sa politique.
  • Retain pour les données qui comptent, ou au minimum un PV passé en Retain après création. La perte par élagage GitOps ou suppression de namespace est un classique.
  • Surveillez le remplissage : un volume plein arrête la base. Le kubelet expose des métriques d'utilisation des volumes (kubelet_volume_stats_*), que le pilote de Scaleway alimente.
  • Le cours Kubernetes : stockage et état approfondit les StatefulSets, les opérateurs de bases de données, les instantanés et la reprise après sinistre.

Exercices

1. Éphémère ou persistant ? (niveau 100). Pour chaque besoin, choisissez le volume : (a) un cache de vignettes que l'application peut recalculer ; (b) un fichier partagé entre le conteneur principal et un conteneur auxiliaire qui l'envoie ailleurs ; (c) les données d'une base de formation ; (d) des fichiers temporaires très fréquemment lus, de quelques Mio.

Solution

(a) emptyDir avec un sizeLimit : perdre le cache au remplacement du pod n'est pas grave. (b) emptyDir, monté dans les deux conteneurs du même pod. (c) Un PVC, avec une politique de récupération adaptée. (d) emptyDir avec medium: Memory et un sizeLimit, en comptant cette taille dans la limite de mémoire du conteneur.

2. La mise à jour bloquée (niveau 200). Après une modification du Deployment postgres (resté en stratégie RollingUpdate), le nouveau pod reste en ContainerCreating sur un autre nœud, et l'ancien tourne toujours. Expliquez, et dites comment débloquer.

Solution

RollingUpdate crée le nouveau pod avant d'arrêter l'ancien. Le volume, RWO ou RWOP, est attaché au nœud de l'ancien pod et utilisé par lui : le nouveau pod ne peut pas l'attacher ni le monter, ses événements montrent FailedAttachVolume (« Waiting for detach » sur 1.35 et plus) ; l'ancien pod n'est pas arrêté tant que le nouveau n'est pas prêt. Interblocage. Débloquer : passer la stratégie en Recreate et appliquer, ou réduire temporairement le Deployment à zéro réplica puis remonter à un. Pour une base, un StatefulSet est l'objet adapté (leçon 10).

3. Le PVC qui ne se lie pas (niveau 200). Sur un cluster neuf, un PVC sans storageClassName reste Pending, et ses événements disent no persistent volumes available for this claim and no storage class is set. Diagnostic et correction ?

Solution

Aucune StorageClass n'est marquée par défaut (annotation storageclass.kubernetes.io/is-default-class: "true"), et le PVC n'en nomme aucune : Kubernetes cherche alors un PV existant sans classe qui convienne, et n'en trouve pas. kubectl get storageclass montre les classes et laquelle est par défaut (mention (default)). Correction : nommer explicitement la classe voulue dans le PVC (le mieux), ou marquer une classe par défaut. Un PVC déjà créé ne peut pas changer de classe : il faut le recréer.

4. La zone perdue (niveau 200). La base de formation tourne sur un cluster Kapsule réparti sur fr-par-1 et fr-par-2. Son volume est en fr-par-1. La zone fr-par-1 devient indisponible. Que se passe-t-il pour la base, et quelles options auriez-vous eues ?

Solution

Le pod de la base disparaît avec son nœud, et ne peut pas être recréé en fr-par-2 : son volume est zonal et n'y est pas attachable. La base est indisponible jusqu'au retour de la zone (et les données récentes sont en jeu si le volume lui-même est atteint). Options : une base répliquée entre zones (deux instances PostgreSQL, chacune avec son volume dans sa zone, réplication gérée par PostgreSQL ou par un opérateur comme CloudNativePG) ; des sauvegardes régulières hors zone (instantanés exportés, sauvegardes logiques vers Object Storage, régional) pour restaurer ailleurs ; ou, le plus simple, une base managée en haute disponibilité hors du cluster.

Récapitulatif

  • Ce qu'un conteneur écrit dans sa couche disparaît avec le pod. emptyDir vit le temps du pod (en mémoire, il compte dans la limite) ; configMap, secret, projected exposent des objets en fichiers.
  • Un PVC demande du stockage, un PV le représente, une StorageClass le fabrique par un pilote CSI : c'est le provisionnement dynamique.
  • RWO : un nœud ; RWOP : un pod ; RWX : plusieurs nœuds, seulement avec un système de fichiers partagé. Un disque bloc Scaleway est RWO ou RWOP, et zonal.
  • WaitForFirstConsumer crée le volume dans la zone du pod ; ensuite, le pod est lié à cette zone.
  • Delete, valeur par défaut, supprime le volume et les données avec le PVC ; Retain les conserve.
  • Agrandir un PVC se fait en place, si la classe le permet ; réduire, jamais. Les instantanés demandent leurs ressources personnalisées et un pilote qui les gère.
  • Un Deployment sur un volume RWO se met à jour en Recreate ; une vraie base se réplique par ses moyens, ou reste managée hors du cluster.

Pour aller plus loin

  • Les pages Persistent Volumes et Storage Classes de la documentation, pour les champs que cette leçon n'a pas couverts (modes de volume bloc, classes d'attributs de volume).
  • Les exemples du dépôt scaleway/scaleway-csi : import de volumes existants, instantanés, chiffrement, choix de la zone et des performances.
  • Le cours Scaleway en pratique, leçon 3, pour ce qu'une base managée prend à sa charge.
  • La leçon suivante, qui présente le StatefulSet, fait pour les applications qui ont besoin d'une identité et d'un volume chacune.
Voir ma constellation →

Sources