Cet article détaille la mise en place d'un provisionnement dynamique de volumes persistants (PV) dans Kubernetes en utilisant un serveur NFS. L'objectif est de permettre aux pods de demander et d'obtenir automatiquement de l'espace de stockage via une classe de stockage (StorageClass).
I. Environnement de déploiement
Les composants et nœuds utilisés pour cette configuration sont les suivants :
- Système d'exploitation : CentOS Linux release 7.9.2009 (Core)
- Kubernetes : v1.30.1
- NFS Server : v1.3.0
La topologie du cluster est composée des nœuds suivants :
- Maître :
master-01(192.168.71.161) - Nœuds de travail :
worker-01(192.168.71.150),worker-02(192.168.71.151)
II. Installation et configuration du serveur NFS
La première étape consiste à installer et configurer le serveur NFS sur le nœud maître.
Installation des paquets NFS
# Installer les utilitaires NFS et rpcbind
yum install -y nfs-utils rpcbind
# Activer et démarrer les services
systemctl enable nfs
systemctl start nfs
Configuration du partage NFS
Créez le répertoire qui sera partagé via NFS et configurez le fichier /etc/exports.
# Créer le répertoire de partage
mkdir -pv /srv/nfs/shared
# Exporter le répertoire avec les permissions appropriées
# Les options rw, sync, no_root_squash sont utilisées pour permettre les écritures, la synchronisation des données et conserver les privilèges root de l'utilisateur distant.
echo "/srv/nfs/shared 192.168.71.0/24(rw,sync,no_root_squash)" > /etc/exports
# Redémarrer le service NFS pour appliquer la configuration
systemctl restart nfs
# Vérifier l'exportation du partage
showmount -e 127.0.0.1
Configuration des nœuds clients NFS
Sur les nœuds de travail, installez les utilitaires NFS et montez le partage distant.
# Installer les utilitaires NFS
yum install -y nfs-utils
# Vérifier la disponibilité du partage depuis le serveur NFS
showmount -e 192.168.71.161
# Activer et démarrer le service NFS (nécessaire pour le montage)
systemctl enable nfs
systemctl start nfs
# Créer le répertoire local de montage
mkdir -pv /mnt/nfs/data
# Monter le partage NFS distant
mount -t nfs 192.168.71.161:/srv/nfs/shared /mnt/nfs/data
Après le montage, un test peut être effectué : créer un fichier sur le serveur NFS devrait le rendre visible sur les nœuds clients, et vice versa.
Pour démonter le partage :
umount /mnt/nfs/data
III. Configuration du stockage Kubernetes
Création d'un espace de noms
Il est recommandé de créer un espace de noms dédié pour les ressources liées au provisionnement NFS.
kubectl create namespace dynamic-storage
3.1. Définition de la classe de stockage (StorageClass)
La StorageClass définit le type de stockage qui sera provisionné. Ici, nous utilisons un provisionneur externe.
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: nfs-dynamic-storage
namespace: dynamic-storage
# Définir comme classe par défaut si vous souhaitez qu'elle soit utilisée sans spécification explicite dans les PVCs
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: nfs.example.com/provisioner # Le nom du provisionneur externe
reclaimPolicy: Retain # Politique de récupération : Retain conserve le volume, Delete le supprime avec le PVC
volumeBindingMode: Immediate # Le volume est lié dès la création du PVC
Appliquez cette définition :
kubectl apply -f nfs-storageclass.yaml
3.2. Configuration des permissions RBAC
Le provisionneur externe nécessite des autorisations spécifiques pour interagir avec l'API Kubernetes (création/suppression de volumes, etc.).
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner-sa
namespace: dynamic-storage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-provisioner-role
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: nfs-provisioner-binding
subjects:
- kind: ServiceAccount
name: nfs-provisioner-sa
namespace: dynamic-storage
roleRef:
kind: ClusterRole
name: nfs-provisioner-role
apiGroup: rbac.authorization.k8s.io
---
# Rôles pour le leader election (si plusieurs instances du provisionneur)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: nfs-provisioner-leader-role
namespace: dynamic-storage
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: nfs-provisioner-leader-binding
namespace: dynamic-storage
subjects:
- kind: ServiceAccount
name: nfs-provisioner-sa
namespace: dynamic-storage
roleRef:
kind: Role
name: nfs-provisioner-leader-role
apiGroup: rbac.authorization.k8s.io
Appliquez ces définitions RBAC :
kubectl apply -f nfs-rbac.yaml
3.3. Déploiement du provisionneur externe NFS
Ce déploiement exécute un pod qui agit comme provisionneur NFS pour Kubernetes. Il écoute les demandes de création de PVC et crée dynamiquement les volumes NFS correspondants.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-external-provisioner
namespace: dynamic-storage
labels:
app: nfs-provisioner
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-provisioner
template:
metadata:
labels:
app: nfs-provisioner
spec:
serviceAccountName: nfs-provisioner-sa # Utilisation du ServiceAccount créé précédemment
containers:
- name: nfs-provisioner
# Utilisation d'une image de provisionneur NFS populaire
image: quay.io/external_storage/nfs-client-provisioner:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-provisioner-storage
mountPath: /persistentvolumes # Chemin où les nouveaux volumes seront créés
env:
- name: PROVISIONER_NAME
value: nfs.example.com/provisioner # Doit correspondre au champ 'provisioner' dans la StorageClass
- name: NFS_SERVER
value: "192.168.71.161" # IP du serveur NFS
- name: NFS_PATH
value: "/srv/nfs/shared" # Chemin du partage NFS sur le serveur
volumes:
- name: nfs-provisioner-storage # Ce volume permet au provisionneur d'écrire sur le partage NFS
nfs:
server: "192.168.71.161"
path: "/srv/nfs/shared"
Appliquez la configuration du déploeiment :
kubectl apply -f nfs-provisioner-deployment.yaml
3.4. Création d'une demande de volume persistant (PVC)
Une fois la StorageClass et le provisionneur configurés, vous pouvez créer un PVC. Kubernetes utilisera la StorageClass par défaut (ou spécifiée) pour demander un volume au provisionneur.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-nfs-pvc
namespace: dynamic-storage
spec:
storageClassName: nfs-dynamic-storage # Spécifie la StorageClass à utiliser
accessModes:
- ReadWriteMany # Mode d'accès : plusieurs nœuds peuvent lire et écrire
resources:
requests:
storage: 1Gi # Taille du volume demandé
Créez le PVC :
kubectl apply -f my-nfs-pvc.yaml
Vérifiez le statut du PVC et le PV qui a été créé dynamiquement :
kubectl get pvc -n dynamic-storage
kubectl get pv
Le PVC devrait passer à l'état Bound, et un nouveau PersistentVolume correspondant devrait apparaître.
Pour supprimer le PVC :
kubectl delete pvc my-nfs-pvc -n dynamic-storage
Si la reclaimPolicy est définie sur Retain, le PV restera après la suppression du PVC. S'il est défini sur Delete, le PV sera supprimé. Le répertoire correspondant sur le serveur NFS sera géré selon la politique configurée dans le provisionneur (souvent, la suppression du PV via le provisionneur entraînera la suppression du répertoire NFS s'il est vide).