Volumes et stockage persistant
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 champsizeLimitborne sa taille ; au-delà, le kubelet évince le pod.emptyDiravecmedium: 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é :
| Mode | Abréviation | Signification |
|---|---|---|
ReadWriteOnce | RWO | Lecture-écriture par un seul nœud à la fois. Plusieurs pods du même nœud peuvent encore y accéder |
ReadWriteOncePod | RWOP | Lecture-écriture par un seul pod dans tout le cluster (stable depuis 1.29, pilotes CSI seulement) |
ReadOnlyMany | ROX | Lecture seule par plusieurs nœuds |
ReadWriteMany | RWX | Lecture-é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 modeWaitForFirstConsumerretarde 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 étatReleased, 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'augmenterspec.resources.requests.storagedu 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'uneVolumeSnapshotClassexiste (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: 5GiReadWriteOncePod: 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: 5432Trois 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.Recreatearrê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épertoirelost+found, etinitdbrefuse d'initialiser un répertoire qui n'est pas vide. - Le Service
postgres: Signalements se connecte àpostgres:5432par 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
Retaincontiennent 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-5kousbs-15kchez Scaleway) et sa politique. Retainpour les données qui comptent, ou au minimum un PV passé enRetainaprè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.
emptyDirvit le temps du pod (en mémoire, il compte dans la limite) ;configMap,secret,projectedexposent 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.
WaitForFirstConsumercré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 ;Retainles 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.
Sources
- Kubernetes, documentation : Volumes
- Kubernetes, documentation : Persistent Volumes
- Kubernetes, documentation : Storage Classes
- Kubernetes, documentation : Volume Snapshots
- Container Storage Interface, spécification
- scaleway/scaleway-csi, README, exemples et code (pkg/driver)
- Scaleway, Managing Block Storage volumes and File Storage filesystems with Scaleway CSI
- Scaleway, Kubernetes Kapsule : clusters multi-AZ (limites)
- kubernetes-sigs/kind, pkg/build/nodeimage/const_storage.go
- kubernetes/kubernetes, contrôleur d'attachement (reconciler.go, release-1.36)
- Docker Official Images, documentation de l'image postgres (PGDATA)