Introduction
Les problèmes réseau des volumes persistants (PV) Kubernetes peuvent se traduire par des réponses d'application lentes, des échecs de montage ou des services inaccessibles. Le dépannage exige une observation méthodique, une compréhension claire des interactions entre composants et des modifications sûres et réversibles. Ce guide fournit des étapes pratiques, illustrées par des exemples, pour diagnostiquer et résoudre les problèmes réseau liés aux volumes persistants dans Kubernetes, en mettant l'accent sur la résolution DNS, la connectivité des ports et le dépannage réseau de bout en bout.
Nous allons suivre un scénario réaliste : un pod d'application ne peut pas accéder à un volume persistant servi sur le réseau, ce qui entraîne des échecs d'écriture intermittents. Vous apprendrez à recueillir les informations de version et d'environnement, à vérifier la configuration, à effectuer des diagnostics, à identifier les modes de défaillance et à suivre une liste de contrôle de récupération. Chaque étape inclut des commandes concrètes, les sorties attendues et les points de décision. L'objectif est la confiance opérationnelle : observer avant de changer, limiter le rayon d'impact, utiliser des espaces réservés pour les données sensibles et vérifier les résultats.
Ce guide s'adresse aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui gèrent des charges de travail avec état dans Kubernetes. Bien que l'accent soit mis sur le réseau des PV, nous aborderons les Persistent Volume Claims (PVC), les StatefulSets et les StorageClasses uniquement lorsqu'ils affectent la connectivité ou la récupération.
Inventaire des versions et de l'environnement
Avant de vous lancer dans le dépannage, établissez la version et la topologie exactes de votre cluster Kubernetes et du backend de stockage. Cela évite les suppositions erronées et vous aide à comparer avec les problèmes connus. Exécutez ces commandes et enregistrez la sortie avec un horodatage.
Informations sur le cluster et les nœuds
kubectl version --short
kubectl get nodes -o wide
Une sortie attendue est similaire à :
Client Version: v1.28.2
Server Version: v1.28.2
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node-1 Ready control-plane 30d v1.28.2 10.0.0.11 <none> Ubuntu 22.04.3 LTS 5.15.0-86-generic containerd://1.7.11
node-2 Ready <none> 30d v1.28.2 10.0.0.12 <none> Ubuntu 22.04.3 LTS 5.15.0-86-generic containerd://1.7.11
Notez la version de Kubernetes (par exemple, 1.28) et le runtime de conteneurs (containerd). Les détails du plugin réseau comptent ; par exemple, avec Calico :
kubectl get pods -n kube-system | grep -E 'calico|kube-proxy'
Sortie attendue :
calico-node-abcde 1/1 Running 0 30d
calico-kube-controllers-12345 1/1 Running 0 30d
kube-proxy-xyz1 1/1 Running 0 30d
Informations sur le backend de stockage
Identifiez la StorageClass et le fournisseur utilisé par votre PV. Supposons que vous utilisiez NFS pour un réseau de stockage partagé. Listez les StorageClasses :
kubectl get storageclass
Sortie attendue :
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client (default) nfs.csi.k8s.io Delete Immediate true 60d
Inspectez ensuite les détails du PV et du PVC :
kubectl get pv
kubectl get pvc -n application-namespace
Exemple de sortie :
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-38b7f2a3-4c5d-4e6f-8a1b-9c0d1e2f3a4b 20Gi RWO Delete Bound app/data-pvc nfs-client 15d
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-pvc Bound pvc-38b7f2a3-4c5d-4e6f-8a1b-9c0d1e2f3a4b 20Gi RWO nfs-client 15d
Enregistrez le point de terminaison du serveur NFS si vous utilisez NFS :
kubectl describe pv pvc-38b7f2a3-4c5d-4e6f-8a1b-9c0d1e2f3a4b | grep -A5 'Source:'
Extrait de sortie attendu :
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 192.168.1.100
Path: /exports/data
ReadOnly: false
Cela vous indique le point de terminaison réseau que vos pods doivent atteindre. Si l'adresse IP du serveur NFS est erronée ou injoignable, tout le réseau des PV échoue.
Vue d'ensemble des pods et des charges de travail
Vérifiez les pods qui utilisent le PVC :
kubectl get pods -n application-namespace -o wide
Exemple :
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
app-db-0 1/1 Running 4 15d 10.244.2.55 node-2 <none> <none>
app-web-7b9c8d5f6-abcde 1/1 Running 0 15d 10.244.1.89 node-1 <none> <none>
Remarquez les redémarrages sur app-db-0 ; cela peut indiquer une connectivité de stockage intermittente.
Observer sans intervenir
À ce stade, n'exécutez que des commandes en lecture seule. Évitez les modifications ou suppressions jusqu'à ce que vous compreniez l'état actuel. Capturez la sortie des commandes suivantes pour une comparaison ultérieure :
kubectl describe pod app-db-0 -n application-namespace
kubectl logs app-db-0 -n application-namespace --tail=50
Si le pod est en boucle de crash, utilisez --previous :
kubectl logs app-db-0 -n application-namespace --previous
Cet inventaire vous donne une base de référence. Passons maintenant à des vérifications de configuration sûres.
Chemin de configuration sûr
Le chemin de configuration sûr garantit que vous effectuez des modifications minimales et bien comprises. Pour le réseau des PV, concentrez-vous sur la StorageClass, le PVC et les configurations de montage du pod.
Inspecter la StorageClass
Pour NFS, vous pouvez avoir une StorageClass personnalisée avec des options de montage qui affectent le comportement réseau. Affichez le YAML :
kubectl get storageclass nfs-client -o yaml
Champs clés :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.1.100
share: /exports
mountOptions:
- nfsvers=4.1
- hard
- timeo=600
- retrans=2
reclaimPolicy: Delete
volumeBindingMode: Immediate
Vérifiez que nfsvers correspond aux capacités du serveur NFS. Une version incompatible (par exemple, le serveur ne prend en charge que NFSv3, mais le client demande la 4.1) provoque des échecs de montage ou de mauvaises performances. De plus, l'option de montage hard signifie que le pod se bloquera indéfiniment en cas de partition réseau ; soft peut être préférable pour une détection de défaillance plus rapide, mais peut entraîner une corruption des données. Décidez en fonction de la tolérance de la charge de travail.
Vérification du PVC et du montage du pod
Vérifiez que le PVC a les bons modes d'accès et qu'il est lié :
kubectl get pvc data-pvc -n application-namespace -o yaml
Recherchez accessModes :
accessModes:
- ReadWriteOnce
Si votre application a besoin d'un stockage partagé (par exemple, plusieurs pods en lecture/écriture), vous avez besoin de ReadWriteMany. Utiliser ReadWriteOnce avec plusieurs réplicas peut entraîner qu'un seul nœud monte avec succès, ce qui provoque des erreurs réseau pour les autres.
Inspectez le montage de volume du pod et les indicateurs de lecture seule :
kubectl get pod app-db-0 -n application-namespace -o yaml | grep -A10 'volumeMounts:'
Extrait attendu :
volumeMounts:
- mountPath: /var/lib/data
name: data
readOnly: false
Assurez-vous que mountPath correspond au chemin attendu par l'application et qu'il n'est pas en lecture seule lorsque des écritures sont nécessaires.
Plus petite modification justifiée
Si vous devez modifier une configuration (par exemple, ajouter l'option de montage soft ou changer la version NFS), mettez à jour la StorageClass avec un patch, mais testez d'abord dans un environnement hors production.
Exemple de patch pour changer nfsvers de 4.1 à 4.0 :
kubectl patch storageclass nfs-client --type='json' -p='[{"op": "replace", "path": "/mountOptions/0", "value": "nfsvers=4.0"}]'
Vérifiez le changement :
kubectl get storageclass nfs-client -o yaml | grep -A5 'mountOptions'
Les nouveaux pods utiliseront l'option mise à jour. Les pods existants doivent être redémarrés pour prendre en compte les changements ; envisagez un redémarrage progressif du StatefulSet.
Test local avec port-forward
Avant d'impliquer des services réseau externes, testez la connectivité localement. Pour un pod qui sert un protocole de fichier réseau ou une API, utilisez kubectl port-forward :
kubectl port-forward pod/app-db-0 -n application-namespace 2049:2049
Ensuite, depuis un autre terminal, testez le montage NFS avec des outils locaux :
sudo mount -t nfs -o nfsvers=4.1 localhost:/exports/data /mnt/test
Si cela échoue, le problème se situe à l'intérieur du cluster, pas dans le réseau externe.
Vérification sans LoadBalancer
Évitez de créer un service LoadBalancer juste pour tester. Utilisez plutôt un service NodePort temporaire ou port-forward. Cela limite l'exposition et les coûts.
Vérification et diagnostics
Maintenant que la configuration est comprise, effectuez des diagnostics actifs pour isoler le problème réseau.
Vérifications de la résolution DNS
De nombreux problèmes réseau de PV proviennent de défaillances DNS, en particulier lorsque le serveur NFS est référencé par nom d'hôte. Tout d'abord, vérifiez les pods CoreDNS :
kubectl get pods -n kube-system -l k8s-app=kube-dns
Attendu :
NAME READY STATUS RESTARTS AGE
coredns-787d4945fb-abcde 1/1 Running 0 30d
coredns-787d4945fb-fghij 1/1 Running 0 30d
Testez la résolution DNS depuis l'intérieur d'un pod. Exécutez nslookup dans le pod de l'application (ou un pod de débogage) :
kubectl exec -it app-db-0 -n application-namespace -- nslookup nfs-server.example.com
Sortie attendue :
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: nfs-server.example.com
Address: 192.168.1.100
Si vous obtenez server can't find nfs-server.example.com: NXDOMAIN, le nom d'hôte n'est pas dans le DNS. Vérifiez si vous devez ajouter une entrée à /etc/hosts via hostAliases dans la spécification du pod ou corriger le DNS externe.
Tests de connectivité des ports
NFS utilise généralement le port TCP/UDP 2049. Testez la connectivité depuis le pod vers le serveur NFS :
kubectl exec -it app-db-0 -n application-namespace -- nc -zvw3 192.168.1.100 2049
Si nc n'est pas installé, utilisez bash avec /dev/tcp :
kubectl exec -it app-db-0 -n application-namespace -- bash -c 'echo > /dev/tcp/192.168.1.100/2049 && echo open || echo closed'
Sortie de succès attendue : open. Si fermé, vérifiez les NetworkPolicies, les règles de pare-feu ou l'état du service du serveur NFS.
Vérifiez les NetworkPolicies qui pourraient bloquer la sortie vers le serveur NFS :
kubectl get networkpolicies -n application-namespace
Si une politique existe, inspectez-la :
kubectl describe networkpolicy allow-nfs -n application-namespace
Assurez-vous que la politique autorise la sortie vers 192.168.1.100/32 sur le port 2049.
Vérifications des endpoints et des services
Si le stockage est exposé via un Service Kubernetes (par exemple, un serveur NFS exécuté en tant que pod), vérifiez les endpoints :
kubectl get endpoints nfs-service -n storage-namespace
Attendu :
NAME ENDPOINTS AGE
nfs-service 10.244.2.10:2049 20d
Si les endpoints sont vides, vérifiez que le sélecteur du service correspond aux étiquettes du pod.
Journaux et événements
Vérifiez les événements du pod pour les erreurs de montage :
kubectl describe pod app-db-0 -n application-namespace | tail -30
Recherchez des messages comme :
Warning FailedMount 2m (x12 over 30m) kubelet MountVolume.SetUp failed for volume "pvc-38b7f2a3..." : mount failed: exit status 32
Mounting command: mount
Mounting arguments: -t nfs 192.168.1.100:/exports/data /var/lib/kubelet/pods/.../volumes/kubernetes.io~nfs/pvc-38b7f2a3...
Output: mount.nfs: access denied by server while mounting 192.168.1.100:/exports/data
Cela indique un problème de permission d'exportation NFS ou une adresse IP client incorrecte dans la configuration d'exportation.
Vérifiez les journaux de kubelet sur le nœud où le pod s'exécute (node-2) :
journalctl -u kubelet -n 50 --no-pager | grep -i 'nfs\|mount'
Cela peut révéler des délais d'attente réseau ou des erreurs RPC.
Débogage du plugin réseau
Si vous utilisez Calico, vérifiez les journaux de calico-node :
kubectl logs -n kube-system calico-node-abcde --tail=50 | grep -i 'nfs\|drop\|deny'
Recherchez les paquets abandonnés en raison de la politique. Vous pouvez également utiliser calicoctl pour vérifier l'évaluation de la politique réseau.
Pod de débogage temporaire
Exécutez un pod temporaire avec des outils réseau pour isoler si le problème est spécifique au pod ou à l'échelle du cluster :
apiVersion: v1
kind: Pod
metadata:
name: debug-network
namespace: application-namespace
spec:
containers:
- name: debug
image: nicolaka/netshoot
command: ["sleep", "3600"]
restartPolicy: Never
Créez-le :
kubectl apply -f debug-pod.yaml
Testez ensuite le montage NFS manuellement dans le pod de débogage :
kubectl exec -it debug-network -n application-namespace -- mount -t nfs 192.168.1.100:/exports/data /mnt
Si cela fonctionne mais que le pod d'application échoue, le problème peut provenir du contexte de sécurité du pod ou de la configuration du montage de volume.
Modes de défaillance et récupération
Comprendre les modes de défaillance courants accélère la récupération. Voici des scénarios spécifiques et comment les résoudre.
Mode de défaillance 1 : Serveur NFS injoignable
Symptômes : les journaux du pod affichent I/O error, le montage se bloque, ou des événements FailedMount avec connection timed out.
Diagnostic :
kubectl exec -it app-db-0 -n application-namespace -- ping -c 3 192.168.1.100
Si le ping échoue, vérifiez le routage réseau : les nœuds du cluster peuvent-ils atteindre le sous-réseau du serveur NFS ? Si le serveur NFS est sur un réseau différent, assurez-vous que les tables de routage et les règles de pare-feu autorisent le trafic.
Récupération : corrigez la connectivité réseau (par exemple, ajoutez une route ou une règle de pare-feu), puis redémarrez le pod :
kubectl delete pod app-db-0 -n application-namespace
Attendez que le StatefulSet le recrée.
Mode de défaillance 2 : Échec de résolution DNS pour le nom d'hôte du serveur NFS
Symptômes : erreurs de montage avec Unable to resolve host ou server not found. Si l'adresse IP du serveur NFS a changé mais que le DNS n'est pas mis à jour.
Diagnostic : confirmez avec nslookup (voir plus tôt).
Récupération : mettez à jour l'enregistrement DNS ou, comme solution immédiate, utilisez l'adresse IP dans la spécification du PV. Pour changer le serveur NFS dans le PV :
kubectl patch pv pvc-38b7f2a3-4c5d-4e6f-8a1b-9c0d1e2f3a4b --type='json' -p='[{"op": "replace", "path": "/spec/nfs/server", "value": "192.168.1.101"}]'
Supprimez ensuite le pod pour le remonter :
kubectl delete pod app-db-0 -n application-namespace
Mode de défaillance 3 : Permissions d'exportation refusées
Symptômes : access denied by server dans la sortie de montage (voir plus tôt).
Diagnostic : comparez la configuration d'exportation NFS sur le serveur. L'exportation doit autoriser les adresses IP des nœuds du pod ou la plage CIDR du réseau du cluster (par exemple, 10.244.0.0/16 pour Calico).
Exemple d'exportation sur le serveur NFS /etc/exports :
/exports/data 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
Si vos pods du cluster utilisent un CIDR différent (par exemple, 10.244.0.0/16), le serveur NFS peut rejeter car l'adresse IP client provient de cette plage. Mettez à jour l'exportation pour inclure ce CIDR :
/exports/data 10.244.0.0/16(rw,sync,no_subtree_check,no_root_squash)
Exécutez ensuite exportfs -ra sur le serveur NFS. Aucun redémarrage de pod n'est nécessaire si le montage réussit à la prochaine tentative.
Mode de défaillance 4 : NetworkPolicy bloquante
Symptômes : le pod peut atteindre le serveur NFS depuis d'autres pods mais pas depuis son propre namespace, ou la connectivité échoue après l'application d'une NetworkPolicy.
Diagnostic : passez en revue les NetworkPolicies comme décrit. Utilisez kubectl describe networkpolicy pour voir les règles. Si une politique de refus global est présente, assurez-vous d'avoir des règles d'autorisation pour NFS.
Récupération : appliquez une nouvelle NetworkPolicy autorisant la sortie vers le serveur NFS :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-nfs-egress
namespace: application-namespace
spec:
podSelector:
matchLabels:
app: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 192.168.1.100/32
ports:
- protocol: TCP
port: 2049
- protocol: UDP
port: 2049
Appliquez et testez la connectivité.
Mode de défaillance 5 : Inadéquation des options de montage
Symptômes : le montage réussit mais les performances sont médiocres, ou des délais d'attente fréquents. Une inadéquation de nfsvers entraîne un repli vers une version plus ancienne ou un échec.
Diagnostic : vérifiez les options de montage de la StorageClass et les versions prises en charge par le serveur NFS. Utilisez rpcinfo -p 192.168.1.100 | grep nfs (depuis un nœud avec accès) pour lister les versions.
Récupération : mettez à jour la StorageClass avec le nfsvers correct et redémarrez les pods.
Liste de contrôle des opérations
Utilisez cette liste de contrôle pour vous assurer de couvrir tous les aspects lors du dépannage réseau des PV.
| Étape | Action | Commande ou vérification | Résultat attendu |
|---|---|---|---|
| 1 | Enregistrer la version du cluster et les nœuds | kubectl version --short, kubectl get nodes -o wide | Tous les nœuds Ready, version cohérente |
| 2 | Identifier le fournisseur de stockage et le backend | kubectl get storageclass, kubectl get pv | Le fournisseur correspond à l'intention (par exemple, nfs.csi.k8s.io), PV Bound |
| 3 | Vérifier la joignabilité du serveur NFS depuis le nœud | ping -c 3 192.168.1.100 depuis le nœud | 0 % de perte de paquets |
| 4 | Vérifier le port NFS ouvert | telnet 192.168.1.100 2049 ou nc -zv | Connexion réussie |
| 5 | Vérifier la résolution DNS dans le pod | kubectl exec <pod> -- nslookup nfs-server.example.com | Renvoie la bonne IP |
| 6 | Tester le montage NFS manuellement dans un pod de débogage | mount -t nfs 192.168.1.100:/exports/data /mnt dans le pod de débogage | Le montage réussit sans erreur |
| 7 | Examiner les événements du pod | kubectl describe pod <pod-name> | Aucun avertissement FailedMount |
| 8 | Vérifier les journaux de kubelet | journalctl -u kubelet -n 50 --no-pager sur le nœud | Aucune erreur de montage |
| 9 | Inspecter les NetworkPolicies | kubectl get networkpolicies -n <ns> | Les règles autorisent le trafic NFS si nécessaire |
| 10 | Confirmer l'état du PV/PVC | kubectl get pv,pvc -n <ns> | Bound et disponible |
| 11 | Valider les options de montage | kubectl get storageclass <name> -o yaml | Les options correspondent aux capacités du serveur |
| 12 | Effectuer une modification test contrôlée | Patcher la StorageClass ou le PV, redémarrer le pod, vérifier le montage | Aucun effet indésirable |
| 13 | Documenter les conclusions et les étapes de récupération | Mettre à jour le runbook | Notes claires |
Exemple d'entrée de runbook
Après avoir résolu un problème (par exemple, permission d'exportation NFS refusée), ajoutez une entrée à votre runbook :
## Incident : le montage du PVC a échoué avec "access denied by server"
Date : 2025-04-02
Cluster : prod-shared
Namespace : application-namespace
PV : pvc-38b7f2a3-4c5d-4e6f-8a1b-9c0d1e2f3a4b
Symptômes : le pod app-db-0 redémarre, l'événement affiche mount.nfs access denied.
Cause racine : l'exportation NFS du serveur n'autorisait que 192.168.1.0/24, mais le CIDR du réseau des pods est 10.244.0.0/16.
Résolution : mise à jour de /etc/exports pour inclure 10.244.0.0/16, exécution d'exportfs -ra, redémarrage du pod.
Vérification : le pod a redémarré avec succès, les écritures de l'application ont repris.
Conclusion
Le dépannage réseau des volumes persistants Kubernetes exige une approche structurée : inventorier l'environnement, vérifier la configuration, exécuter des diagnostics ciblés, comprendre les modes de défaillance et suivre une liste de contrôle de récupération. En utilisant les commandes et les exemples concrets de ce guide, vous pouvez rapidement déterminer si le problème réside dans le DNS, la connectivité des ports, les options de montage, les politiques réseau ou les permissions du backend.
Observez toujours avant d'intervenir. Capturez l'état actuel, effectuez une petite modification à la fois et vérifiez le résultat. Gardez les données sensibles hors des journaux et des commandes en utilisant des espaces réservés et en les masquant lors du partage. Avec ces pratiques, vous réduirez les temps d'arrêt et améliorerez la fiabilité de vos applications avec état.
Comme prochaine étape, choisissez une vérification à faible risque de la liste de contrôle des opérations, exécutez-la dans votre environnement et documentez le résultat. Au fil du temps, vous construirez un playbook de dépannage robuste pour le réseau des volumes persistants Kubernetes.