## Introduction

Les volumes Kubernetes sont une source fréquente de frustration. Un pod peut rester en état `ContainerCreating`, une application peut planter avec une erreur de permission, ou les données peuvent disparaître après un redémarrage. Le dépannage exige une approche systématique : identifier la version et l'environnement, comprendre le cycle de vie des volumes, inspecter les bons objets Kubernetes et vérifier les correctifs avec des commandes précises et les sorties attendues.

Ce guide fournit un dépannage pratique, axé sur les commandes, pour les volumes Kubernetes. Il s'adresse aux développeurs, aux ingénieurs DevOps et aux équipes techniques de startups qui gèrent des clusters Kubernetes et doivent résoudre rapidement les problèmes de volumes. Nous couvrons les PersistentVolumes (PV), les PersistentVolumeClaims (PVC), les StorageClasses et les types de volumes courants comme hostPath, emptyDir et les disques des fournisseurs cloud. Tout au long, nous insistons sur la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact et vérifier les résultats.

## Inventaire de la version et de l'environnement

Avant de dépanner, rassemblez des informations sur le cluster Kubernetes et le sous-système de stockage.

**Vérifiez la version de Kubernetes :**
```bash
kubectl version --short
```
Exemple de sortie :
```
Client Version: v1.26.5
Server Version: v1.26.7
```

**Vérifiez les nœuds du cluster et les éventuels labels liés aux volumes :**
```bash
kubectl get nodes -o wide
```
Notez les nœuds ayant des labels de zone ou de région spécifiques qui peuvent affecter l'attachement des volumes.

**Identifiez le fournisseur de stockage.** Pour les clusters basés sur le cloud, déterminez le pilote CSI utilisé :
```bash
kubectl get csidrivers
```
Exemple :
```
NAME                     ATTACH    PODINFOONMOUNT   STORAGECAPACITY
pd.csi.storage.gke.io    true      true             true
```
Pour les environnements sur site, vérifiez si un provisionneur local ou NFS est configuré en listant les StorageClasses (voir ci-dessous).

**Passez en revue les StorageClasses existantes :**
```bash
kubectl get storageclass
```
La sortie peut montrer des classes comme `standard (default)`, `premium-rwo`, etc. Vérifiez la classe par défaut :
```bash
kubectl get storageclass -o jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}'
```

**Vérifiez les PV et PVC existants :**
```bash
kubectl get pv,pvc -A
```
Cela affiche tous les volumes et réclamations, leur statut, leur capacité et leur état de liaison.

**Prérequis pour un dépannage efficace :**
- Accès au cluster avec `kubectl` configuré.
- Autorisations pour visualiser et décrire les ressources de stockage (généralement cluster-admin ou un rôle avec les droits get/list/watch sur les persistentvolumes, persistentvolumeclaims, storageclasses, pods, events).
- Compréhension de la manière dont le stockage est provisionné dans votre environnement (statique vs dynamique).

Pour l'observation initiale, évitez de faire des modifications. Commencez par des commandes en lecture seule :
```bash
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
```
Les événements contiennent souvent des indices sur les échecs de volume. Pour un pod spécifique :
```bash
kubectl describe pod <pod-name> -n <namespace>
```

## Comprendre le cycle de vie des volumes

Le stockage Kubernetes repose sur trois objets principaux :

1. **PersistentVolume (PV) :** une ressource de cluster représentant un stockage physique (par exemple, un volume EBS AWS, un disque GCE PD, un hostPath).
2. **PersistentVolumeClaim (PVC) :** une demande de stockage par un utilisateur, spécifiant la taille et les modes d'accès.
3. **StorageClass :** définit les paramètres du provisionneur et la politique de récupération ; permet le provisionnement dynamique.

Le cycle de vie en termes simples :
- Un PVC est créé ; le plan de contrôle trouve ou provisionne dynamiquement un PV correspondant.
- Le PVC se lie au PV.
- Un pod monte le PVC.
- Lorsque le pod est supprimé, le PVC reste (sauf si la politique de récupération le supprime).

Le dépannage consiste souvent à déterminer à quelle étape de ce cycle de vie l'échec se produit.

## Types de volumes courants et schémas de défaillance

### hostPath
Utilisé pour le développement et les tests sur un seul nœud. Les fichiers sont stockés sur le nœud. Si le nœud tombe en panne, les données peuvent être perdues. Les pods utilisant hostPath peuvent ne pas être replanifiés sur d'autres nœuds (sauf en utilisant `nodeSelector` ou des affinités). Ne convient pas à la production.

**Problèmes typiques :**
- Le chemin n'existe pas sur le nœud.
- Permission refusée car le pod s'exécute en tant que non-root alors que le répertoire hostPath appartient à root.
- Persistance des données entre les redémarrages du pod sur le même nœud, mais pas après le redémarrage du nœud.

### emptyDir
Stockage temporaire limité à la durée de vie d'un pod. Créé lorsque le pod est assigné à un nœud, supprimé lorsque le pod est retiré. Utilisé pour l'espace de travail temporaire, le cache.

**Problèmes :**
- Perte de données si le pod est évincé ou si le nœud est drainé.
- Le dépassement de la limite de stockage éphémère du nœud déclenche une éviction.

### Système de fichiers réseau (NFS)
Permet à plusieurs pods de lire/écrire simultanément sur plusieurs nœuds. Nécessite un serveur NFS et un support client. Courant dans les environnements existants n'utilisant pas le provisionnement dynamique.

**Problèmes :**
- Échec du montage en raison de paquets NFS manquants ou d'un pare-feu bloquant les ports 111 et 2049.
- Problèmes de performance.

### Volumes des fournisseurs cloud (EBS, GCE PD, Azure Disk)
Stockage en bloc persistant dans le cloud, généralement provisionné dynamiquement via des pilotes CSI. Supporte uniquement `ReadWriteOnce` (peut être monté sur un seul nœud à la fois), à l'exception de certaines nouvelles capacités.

**Problèmes :**
- Volume bloqué en état `Attaching` en raison d'une incompatibilité de zone entre le nœud et le volume.
- Pod reste en `ContainerCreating` pendant longtemps, puis expire.
- Défaillance du nœud empêchant le détachement du volume.
- Coût : volumes orphelins après la suppression du PVC si la politique de récupération n'est pas correctement définie.

## Procédures de dépannage étape par étape

Nous suivrons un pod bloqué en `ContainerCreating` avec des problèmes de volume.

### Étape 1 : Identifier le pod et ses volumes

```bash
kubectl get pods -n <namespace>
```
Trouvez le pod problématique (par exemple, `my-app-6948c7d9d-xxxxx`).

Décrivez le pod :
```bash
kubectl describe pod my-app-6948c7d9d-xxxxx -n <namespace>
```

Regardez les sections `Volumes:` et `Conditions:`. Les événements en bas révèlent souvent des erreurs comme :
```
Warning  FailedMount  2m   kubelet  Unable to attach or mount volumes: unmounted volumes=[data], unattached volumes=[data default-token-xxxxx]: timed out waiting for the condition
```

Cela indique que le volume `data` n'a pas pu être monté. Notez le nom et le type du volume.

### Étape 2 : Inspecter le PVC et le PV

À partir de la description du pod, identifiez le nom de la réclamation. Ensuite :
```bash
kubectl describe pvc <claim-name> -n <namespace>
```
Vérifiez `Status`, `Volume`, `Capacity`, `Access Modes` et les événements.

Si le PVC est en attente (`Pending`), aucun PV n'est lié. Voir le dépannage des PVC en attente ci-dessous.

S'il est lié, obtenez le nom du PV dans `Volume:` et décrivez-le :
```bash
kubectl describe pv <pv-name>
```
Recherchez le statut, la politique de récupération et les messages éventuels sur la disponibilité.

### Étape 3 : Vérifier la StorageClass et le provisionneur

Si le provisionnement est dynamique, identifiez la StorageClass utilisée par le PVC (le cas échéant) :
```bash
kubectl get pvc <claim-name> -o jsonpath='{.spec.storageClassName}'
```
Décrivez ensuite la StorageClass :
```bash
kubectl describe storageclass <sc-name>
```
Vérifiez que le provisionneur est valide et qu'aucun paramètre ne peut causer un échec.

### Étape 4 : Examiner les événements

```bash
kubectl get events -n <namespace> --field-selector involvedObject.name=<pod-name> --sort-by='.lastTimestamp'
```
Les événements contiennent souvent des messages d'erreur précis provenant du plugin de volume ou du pilote CSI.

### Étape 5 : Vérifier les journaux du kubelet (si accès au nœud)

Sur le nœud où le pod est planifié (à partir de `kubectl get pod -o wide`), examinez les journaux du kubelet pour les échecs de montage de volume.

Pour les nœuds basés sur systemd :
```bash
journalctl -u kubelet -f | grep -i volume
```

## Modes de défaillance courants et récupération

### PVC bloqué en attente (Pending)

**Causes possibles :**
- Aucune StorageClass spécifiée et aucune StorageClass par défaut définie.
- Aucun PV disponible correspondant à la demande.
- Provisionneur non opérationnel ou mal configuré.
- Capacité insuffisante.

**Diagnostics :**
```bash
kubectl describe pvc <claim-name>
```
Recherchez des événements comme :
```
Warning  ProvisioningFailed  3m  persistentvolume-controller  storageclass.storage.k8s.io "standard" not found
```

**Récupération :**
- Si vous utilisez le provisionnement dynamique, assurez-vous que la StorageClass existe et qu'elle est par défaut si elle n'est pas spécifiée.
- Si le provisionnement est statique, créez un PV avec une capacité et des modes d'accès correspondants.
- Vérifiez l'état du pod du provisionneur (pour CSI) : `kubectl get pods -n kube-system | grep csi`.

**Exemple de correctif :**
Créez une StorageClass par défaut :
```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
```
Remarque : `no-provisioner` nécessite la création manuelle de PV, mais cela démontre la définition d'une classe par défaut. Pour la production, utilisez un provisionneur approprié.

### Pod bloqué en ContainerCreating avec FailedMount

**Symptômes :** le pod ne démarre pas, la description montre `FailedMount` avec la raison `Unable to attach or mount volumes`.

**Causes possibles :**
- Volume non attaché au nœud (par exemple, incompatibilité de zone).
- Volume déjà monté par un autre nœud (conflit ReadWriteOnce).
- Options de montage invalides.
- Problèmes de permission sur hostPath.

**Diagnostics :**
- Vérifiez le nœud où le pod est assigné et la zone de disponibilité du volume (pour les volumes cloud).
- Pour les volumes cloud, utilisez la CLI du cloud pour inspecter l'état du volume (par exemple, `aws ec2 describe-volumes`, `gcloud compute disks describe`).
- Recherchez des événements indiquant une erreur `Multi-Attach`.

**Récupération :**
- Assurez-vous que le nœud et le volume sont dans la même zone. Cela peut nécessiter de déplacer le pod vers le bon nœud ou de créer le volume dans la bonne zone.
- Si le volume est bloqué attaché à un nœud mort, forcez le détachement : utilisez la console ou la CLI du fournisseur cloud pour détacher le volume.
- Pour hostPath, assurez-vous que le chemin existe et que les permissions permettent à l'utilisateur du conteneur d'accéder.

**Exemple : forcer le détachement d'un volume EBS depuis AWS :**
```bash
aws ec2 detach-volume --volume-id vol-1234567890abcdef0 --force
```
Attendez ensuite que l'état soit `available`.

### Erreurs de permission refusée

Souvent observées avec hostPath ou NFS où le serveur applique `root_squash` ou des identifiants d'utilisateur différents.

**Diagnostics :**
- Les journaux du pod peuvent montrer `Permission denied`.
- Exécutez `ls -l` dans le conteneur avec `kubectl exec` pour vérifier la propriété.

**Récupération :**
- Pour hostPath, modifiez les permissions du répertoire hôte, ou exécutez le conteneur en tant que root (si acceptable), ou utilisez `fsGroup` dans le contexte de sécurité du pod.
- Pour NFS, configurez les exports avec `no_root_squash` ou ajustez les identifiants d'utilisateur.

**Exemple : définir fsGroup dans le spec du pod :**
```yaml
spec:
  securityContext:
    fsGroup: 2000
```
Cela change la propriété de groupe des fichiers du volume en GID 2000.

### Perte ou corruption de données

**Symptômes :** l'application signale des fichiers manquants, corruption de base de données.

**Causes possibles :**
- Pod avec plusieurs réplicas partageant un volume ReadWriteOnce (un seul nœud peut monter ; l'autre échoue ou les données se corrompent si le système de fichiers n'est pas conçu pour un accès concurrent).
- Politique de récupération définie sur `Delete` et PVC supprimé accidentellement.
- Défaillance du nœud provoquant une incohérence du système de fichiers.

**Récupération :**
- Utilisez toujours le mode d'accès approprié : `ReadWriteMany` pour le stockage partagé (NFS, GlusterFS).
- Définissez la politique de récupération sur `Retain` pour les volumes importants afin d'éviter la suppression automatique.
- Prenez régulièrement des instantanés (par exemple, des instantanés CSI).
- Si vous utilisez un stockage en bloc pour des bases de données, assurez-vous que le pod est replanifié sur le même nœud (utilisez des affinités de nœud) pour éviter la corruption multi-nœuds.

**Exemple d'instantané (utilisant l'API VolumeSnapshot) :**
```yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: my-snapshot
spec:
  volumeSnapshotClassName: csi-hostpath-snapclass
  source:
    persistentVolumeClaimName: my-pvc
```

### Problèmes d'expansion de volume

L'expansion d'un PVC peut échouer si la StorageClass ne permet pas l'expansion ou si le pilote CSI ne la supporte pas.

**Vérifiez si la StorageClass permet l'expansion :**
```bash
kubectl get storageclass <sc-name> -o jsonpath='{.allowVolumeExpansion}'
```
Si ce n'est pas `true`, l'expansion est impossible.

**Récupération :** créez un nouveau PVC avec une taille supérieure et migrez les données, ou activez l'expansion en modifiant la StorageClass (si le pilote le supporte).

## Pièges courants et comment les éviter

1. **Ignorer les modes d'accès :** un PVC avec `ReadWriteOnce` ne peut pas être monté par plusieurs nœuds. Les déploiements avec plusieurs réplicas nécessitent `ReadWriteMany` ou l'utilisation de contraintes de répartition topologique/affinités pour planifier sur le même nœud. **Éviter :** passez en revue les modes d'accès pour votre charge de travail.

2. **Ne pas définir de StorageClass par défaut :** dans de nombreux clusters, sans StorageClass par défaut, les PVC sans `storageClassName` restent en attente. **Éviter :** spécifiez toujours explicitement `storageClassName` ou définissez une classe par défaut.

3. **Utiliser hostPath en production :** hostPath lie le pod à un nœud et peut causer des problèmes de permission et des risques de sécurité. **Éviter :** utilisez le provisionnement dynamique ou des volumes persistants locaux pour un stockage affinitaire au nœud.

4. **Oublier les instantanés et les sauvegardes de volumes :** Kubernetes ne sauvegarde pas automatiquement les volumes. La perte de données est courante après une suppression. **Éviter :** mettez en œuvre des stratégies d'instantanés et de sauvegarde.

5. **Mauvaise configuration de la politique de récupération :** la politique de récupération par défaut pour les volumes provisionnés dynamiquement est généralement `Delete`. Si vous supprimez un PVC, le volume sous-jacent est supprimé. **Éviter :** définissez `Retain` pour les données critiques et nettoyez manuellement les volumes.

6. **Incompatibilité de zone dans le cloud :** la création d'une StorageClass avec `volumeBindingMode: Immediate` peut provisionner un volume dans une zone aléatoire, puis le pod planifié dans une autre zone ne peut pas s'attacher. **Éviter :** utilisez `WaitForFirstConsumer` pour retarder le provisionnement jusqu'à ce que le pod soit planifié, assurant ainsi l'alignement des zones.

## Liste de vérification opérationnelle

Pour chaque session de dépannage, suivez cette liste :

- [ ] **Vérifier la version du cluster et les pilotes de stockage :** `kubectl version --short`, `kubectl get csidrivers`. Enregistrez les sorties.
- [ ] **Lister toutes les ressources de stockage :** `kubectl get pv,pvc,sc -A`. Vérifiez les statuts.
- [ ] **Décrire le pod en échec :** `kubectl describe pod <pod-name> -n <namespace>`. Notez les montages de volume et les événements.
- [ ] **Décrire le PVC :** `kubectl describe pvc <claim-name> -n <namespace>`. Notez la phase et les événements.
- [ ] **Décrire le PV (s'il est lié) :** `kubectl describe pv <pv-name>`. Vérifiez la politique de récupération et la capacité.
- [ ] **Vérifier les événements triés par heure :** `kubectl get events -n <namespace> --sort-by='.lastTimestamp'`. Recherchez les avertissements.
- [ ] **Valider les affinités de nœud et les zones :** `kubectl get nodes -o wide` et les informations de zone des volumes cloud. Assurez-vous que le nœud du pod et la zone du volume correspondent.
- [ ] **Vérifier les journaux du kubelet sur le nœud :** `journalctl -u kubelet -f` pendant la reproduction de la tentative de montage.
- [ ] **Tester avec un pod minimal :** créez un pod simple utilisant le même PVC pour isoler les problèmes spécifiques à l'application.
- [ ] **Après avoir appliqué le correctif, vérifier :** `kubectl get pod -n <namespace>` montre l'état Running, et `kubectl exec` dans le pod pour vérifier l'accès aux fichiers (`ls -l /mount/path`).
- [ ] **Documenter l'incident :** enregistrez les commandes exécutées, les constatations et le correctif appliqué pour référence future.

## Conclusion

Le dépannage des volumes Kubernetes exige une approche méthodique : comprendre l'environnement, identifier le composant en cause, utiliser des diagnostics précis et appliquer des correctifs minimaux avec vérification. Les commandes et exemples de ce guide fournissent une base. Adaptez-les à votre fournisseur de stockage et à la configuration de votre cluster.

N'oubliez pas de prioriser la sécurité : ne supprimez jamais de volumes ni ne modifiez les politiques de récupération sans en comprendre les conséquences. Utilisez des instantanés et des sauvegardes pour éviter la perte de données. Avec la pratique, vous résoudrez efficacement les problèmes de volumes et maintiendrez vos applications en bon état de fonctionnement.

## Ressources supplémentaires

Bien que ce guide couvre des scénarios courants, reportez-vous à la documentation officielle de Kubernetes pour des informations approfondies :
- [Volumes persistants](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
- [Classes de stockage](https://kubernetes.io/docs/concepts/storage/storage-classes/)
- [Instantanés de volumes](https://kubernetes.io/docs/concepts/storage/volume-snapshots/)

Consultez également la documentation de votre fournisseur cloud pour les spécificités du pilote CSI et les outils de dépannage.