Volumes et Stockage
1 - Introduction
Les conteneurs sont éphémères par nature. Pour persister les données, Kubernetes propose un système de volumes flexible.
2 - Types de Volumes
2.1 emptyDir
Volume éphémère créé quand un Pod est assigné à un Node.
apiVersion: v1
kind: Pod
metadata:
name: shared-storage
spec:
containers:
# Conteneur qui écrit
- name: writer
image: busybox
command: ['sh', '-c', 'while true; do date >> /data/log.txt; sleep 5; done']
volumeMounts:
- name: shared-data
mountPath: /data
# Conteneur qui lit
- name: reader
image: busybox
command: ['sh', '-c', 'tail -f /data/log.txt']
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
emptyDir: {}
# Optionnel: stocker en RAM
# emptyDir:
# medium: Memory
# sizeLimit: 100Mi
2.2 hostPath
Monte un répertoire du Node hôte.
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: host-data
mountPath: /data
volumes:
- name: host-data
hostPath:
path: /var/data
type: DirectoryOrCreate # Directory, File, Socket, etc.
hostPath pose des risques de sécurité et n'est pas recommandé en production. Utilisez-le uniquement pour des cas spécifiques (DaemonSets, monitoring).
2.3 configMap et secret
Déjà couverts dans le chapitre précédent.
volumes:
- name: config-vol
configMap:
name: app-config
- name: secret-vol
secret:
secretName: app-secrets
2.4 projected
Combine plusieurs sources dans un seul volume.
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
volumeMounts:
- name: all-in-one
mountPath: /etc/config
volumes:
- name: all-in-one
projected:
sources:
- configMap:
name: app-config
- secret:
name: app-secrets
- downwardAPI:
items:
- path: labels
fieldRef:
fieldPath: metadata.labels
3 - Persistent Volumes (PV)
3.1 Qu'est-ce qu'un PV ?
Un PersistentVolume est une ressource de stockage provisionnée dans le cluster.
3.2 Créer un PV statique
# pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
labels:
type: nfs
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
nfs:
server: 192.168.1.100
path: /exports/data
---
# pv-local.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- worker-1
3.3 Access Modes
| Mode | Abréviation | Description |
|---|---|---|
| ReadWriteOnce | RWO | Lecture/écriture par un seul Node |
| ReadOnlyMany | ROX | Lecture seule par plusieurs Nodes |
| ReadWriteMany | RWX | Lecture/écriture par plusieurs Nodes |
| ReadWriteOncePod | RWOP | Lecture/écriture par un seul Pod |
3.4 Reclaim Policies
| Policy | Description |
|---|---|
| Retain | Garde les données après suppression du PVC |
| Delete | Supprime le volume et les données |
| Recycle | Efface les données (deprecated) |
4 - Persistent Volume Claims (PVC)
4.1 Créer un PVC
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-storage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual
# Optionnel: sélectionner un PV spécifique
selector:
matchLabels:
type: nfs
4.2 Utiliser un PVC dans un Pod
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: postgres:14
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-storage
4.3 Cycle de vie PV/PVC
5 - Storage Classes
5.1 Provisionnement dynamique
Les StorageClasses permettent le provisionnement automatique de PV.
5.2 Créer une StorageClass
# AWS EBS
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-storage
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
---
# GCP Persistent Disk
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd-storage
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
---
# Azure Disk
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: azure-premium
provisioner: disk.csi.azure.com
parameters:
skuName: Premium_LRS
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
5.3 Utiliser une StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: fast-storage # Référence la StorageClass
5.4 StorageClass par défaut
# Voir les StorageClasses
kubectl get storageclass
# Définir comme défaut
kubectl patch storageclass fast-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
6 - Volume Expansion
6.1 Agrandir un PVC
# La StorageClass doit avoir allowVolumeExpansion: true
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: expandable-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi # Initialement 5Gi
storageClassName: fast-storage
# Modifier la taille
kubectl patch pvc expandable-pvc -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
# Vérifier
kubectl get pvc expandable-pvc
7 - StatefulSets et stockage
7.1 VolumeClaimTemplates
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
# Crée automatiquement un PVC par replica
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-storage
resources:
requests:
storage: 10Gi
8 - CSI (Container Storage Interface)
8.1 Qu'est-ce que CSI ?
CSI est le standard pour connecter des systèmes de stockage à Kubernetes.
8.2 Drivers CSI populaires
| Driver | Storage |
|---|---|
| ebs.csi.aws.com | AWS EBS |
| disk.csi.azure.com | Azure Disk |
| pd.csi.storage.gke.io | GCP Persistent Disk |
| cephfs.csi.ceph.com | CephFS |
| nfs.csi.k8s.io | NFS |
8.3 Installer un driver CSI (exemple AWS EBS)
# Ajouter le repo Helm
helm repo add aws-ebs-csi-driver https://kubernetes-sigs.github.io/aws-ebs-csi-driver
# Installer
helm install aws-ebs-csi-driver aws-ebs-csi-driver/aws-ebs-csi-driver \
--namespace kube-system \
--set controller.serviceAccount.create=true \
--set controller.serviceAccount.name=ebs-csi-controller-sa
9 - Volume Snapshots
9.1 Créer un Snapshot
# VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-snapclass
driver: ebs.csi.aws.com
deletionPolicy: Delete
---
# VolumeSnapshot
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: pvc-snapshot
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: my-pvc
9.2 Restaurer depuis un Snapshot
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restored-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: fast-storage
dataSource:
name: pvc-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
10 - Exemple complet : Base de données PostgreSQL
# Secret pour le mot de passe
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
stringData:
password: supersecret123
---
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: postgres-storage
provisioner: ebs.csi.aws.com
parameters:
type: gp3
reclaimPolicy: Retain
allowVolumeExpansion: true
---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: postgres-storage
---
# Deployment PostgreSQL
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres-data
---
# Service
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
type: ClusterIP
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
Résumé
Dans ce chapitre, nous avons appris :
- Les différents types de volumes (emptyDir, hostPath, etc.)
- Les Persistent Volumes et Persistent Volume Claims
- Le provisionnement dynamique avec StorageClasses
- L'expansion de volumes
- Les StatefulSets et volumeClaimTemplates
- Les drivers CSI et snapshots
Prochaine étape
Dans le prochain chapitre, nous explorerons les Namespaces et RBAC pour l'isolation et la sécurité.
→ Chapitre suivant : Namespaces et RBAC