## Introduction

Les Storage Classes Kubernetes permettent aux administrateurs de cluster de définir le type de stockage disponible pour les charges de travail sans coder en dur les détails du stockage dans les manifestes d’application. Une Storage Class définit un provisionneur, des paramètres comme le type de disque ou le facteur de réplication, et une politique de récupération. Les développeurs demandent du stockage via des PersistentVolumeClaims (PVC) qui référencent une Storage Class, et Kubernetes provisionne dynamiquement un PersistentVolume (PV) correspondant. Cette séparation de l’intention et de l’implémentation réduit la charge opérationnelle et permet des configurations portables entre fournisseurs cloud et solutions sur site. Un modèle mental clair des composants et du flux de requêtes évite les retouches lors du diagnostic des échecs de provisionnement, comme le notent les praticiens qui séparent les étapes de recherche, de configuration et de publication pour la documentation sur le stockage.

Dans ce guide, nous examinons l’architecture derrière les Storage Classes, y compris le flux de contrôle depuis la création du PVC jusqu’à l’attachement du volume. Nous mettrons en place une implémentation ciblée utilisant le provisionneur intégré standard kubernetes.io/aws-ebs dans un cluster EKS hypothétique (Kubernetes v1.27), puis nous vérifierons le provisionnement dynamique avec de vraies commandes et leurs sorties. Nous couvrons les modes de défaillance courants comme les incompatibilités de zones et les permissions, et fournissons des étapes de restauration et de récupération. Enfin, une checklist opérationnelle vous aide à maintenir la configuration de stockage en bonne santé.

## Inventaire des versions et de l’environnement

Avant de créer une Storage Class, confirmez que la version de votre cluster Kubernetes, votre fournisseur cloud et vos pilotes CSI (si utilisés) répondent aux exigences. Le provisionnement dynamique de volumes est stable depuis Kubernetes 1.6, mais les fonctionnalités spécifiques au fournisseur évoluent. Pour ce guide, nous supposons :

- Version Kubernetes : v1.27 (EKS 1.27 hypothétique)
- Fournisseur cloud : AWS, utilisant le provisionneur EBS intégré `kubernetes.io/aws-ebs`
- Nœuds : trois nœuds travailleurs dans une seule zone de disponibilité (us-east-1a) pour simplifier les attachements ; notez que les volumes EBS sont spécifiques à une zone.
- Le compte de service par défaut pour kube-controller-manager a la permission de créer des volumes EBS via l’IAM du fournisseur cloud (dans EKS, le rôle d’instance de nœud ou un rôle IRSA dédié doit avoir `ec2:CreateVolume`, `ec2:AttachVolume`, etc.).
- Une Storage Class nommée `gp2-encrypted` démontrera le chiffrement et la sélection du type.

Vérifiez la version de votre cluster et vos nœuds :

```bash
kubectl version --short
kubectl get nodes -o wide
```

Sortie attendue pour la version (le format réel peut varier) :

```
Client Version: v1.27.3
Kustomize Version: v5.0.3
Server Version: v1.27.4
```

Pour les nœuds, confirmez que la colonne zone de disponibilité correspond à votre zone EBS prévue (par exemple, `us-east-1a`). Si les nœuds s’étendent sur plusieurs zones, définissez des Storage Classes spécifiques à la zone ou utilisez un pilote CSI conscient de la topologie. Une approche pilote étroite réduit les risques ; commencez avec une seule Storage Class, un seul namespace et un PVC d’application avant d’étendre.

## Chemin de configuration sûr

Commencez avec une Storage Class qui utilise un provisionneur bien connu et des paramètres conservateurs. Évitez de définir `allowVolumeExpansion` à `true` avant d’avoir testé le redimensionnement avec votre pilote CSI. Utilisez explicitement `volumeBindingMode: WaitForFirstConsumer` pour garantir que le volume est créé dans la même zone que le pod, évitant ainsi les échecs d’attachement inter-zones.

Créez le manifeste de Storage Class `gp2-sc.yaml` :

```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2-encrypted
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  fsType: ext4
  encrypted: "true"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
```

Appliquez-le :

```bash
kubectl apply -f gp2-sc.yaml
```

Vérifiez la classe :

```bash
kubectl get storageclass gp2-encrypted
```

Sortie attendue :

```
NAME            PROVISIONER          RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2-encrypted   kubernetes.io/aws-ebs   Retain          WaitForFirstConsumer   false                  10s
```

Le mode `WaitForFirstConsumer` retarde la création du volume jusqu’à ce qu’un pod utilisant le PVC soit planifié, garantissant que le volume est créé dans la zone du nœud du pod. Le paramètre `encrypted: "true"` déclenche le chiffrement du volume EBS en utilisant la clé KMS par défaut pour EBS.

Ensuite, créez un namespace et un PVC pour tester le provisionnement :

```bash
kubectl create namespace storage-test
cat <<EOF | kubectl apply -n storage-test -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp2-encrypted
  resources:
    requests:
      storage: 1Gi
EOF
```

Initialement, le PVC reste à l’état Pending car aucun pod ne l’a consommé :

```bash
kubectl get pvc -n storage-test test-pvc
```

Sortie :

```
NAME      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
test-pvc  Pending                       gp2-encrypted                  10s
```

Déployez maintenant un pod trivial (par exemple, busybox) qui monte le PVC :

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: app
    image: busybox
    command: ["sleep", "3600"]
    volumeMounts:
    - mountPath: "/data"
      name: data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: test-pvc
```

Appliquez-le :

```bash
kubectl apply -n storage-test -f test-pod.yaml
```

Attendez quelques secondes et vérifiez à nouveau le PVC :

```bash
kubectl get pvc -n storage-test test-pvc
```

Sortie attendue après provisionnement :

```
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
test-pvc  Bound    pvc-0c8e5e9f-3a7f-4c3b-8f0e-123456789abc   1Gi        RWO            gp2-encrypted   45s
```

Le volume est maintenant lié à un PV. Vérifiez les détails du PV :

```bash
kubectl get pv pvc-0c8e5e9f-3a7f-4c3b-8f0e-123456789abc
```

La sortie inclut l’ID du volume EBS AWS et la zone.

Ce chemin ciblé utilise le provisionneur intégré pour plus de simplicité. Pour la production, envisagez le pilote EBS CSI (`ebs.csi.aws.com`) qui offre une meilleure intégration, mais les concepts restent les mêmes.

## Vérification et diagnostic

Après que le pod est en cours d’exécution, confirmez que le volume est attaché et monté. Tout d’abord, obtenez le statut du pod :

```bash
kubectl get pod -n storage-test test-pod
```

Attendu :

```
NAME      READY   STATUS    RESTARTS   AGE
test-pod  1/1     Running   0          2m
```

Vérifiez l’attachement du volume du point de vue du nœud. Connectez-vous en SSH au nœud (ou utilisez `kubectl debug node`), puis exécutez `lsblk` ou `df -h` pour voir le système de fichiers monté. Alternativement, exécutez dans le pod :

```bash
kubectl exec -n storage-test test-pod -- df -h /data
```

Sortie :

```
Filesystem      Size  Used Available Use% Mounted on
/dev/xvdba      976M  1.3M    958M   0% /data
```

Pour confirmer le chiffrement, utilisez l’AWS CLI depuis un emplacement avec permissions :

```bash
aws ec2 describe-volumes --volume-ids vol-0abc123def456ghij --query 'Volumes[0].Encrypted'
```

Attendu : `true`.

Vérifiez les annotations de la Storage Class et les événements pour tout avertissement :

```bash
kubectl describe storageclass gp2-encrypted
kubectl get events -n storage-test --field-selector involvedObject.name=test-pvc
```

Les événements peuvent montrer `ProvisioningSucceeded` ou des erreurs.

## Pièges courants et comment les éviter

Même avec une architecture solide, des erreurs de configuration peuvent causer des maux de tête. Voici les pièges fréquents, pourquoi ils se produisent et comment les éviter ou s’en remettre.

### 1. Utiliser `volumeBindingMode: Immediate` dans les clusters multi-zones

**Pourquoi cela arrive :** Avec `Immediate`, le PV est créé dès que le PVC est soumis, sans attendre qu’un pod soit planifié. Dans les clusters multi-zones, le volume peut être créé dans une zone où aucun nœud ne peut l’attacher, laissant le pod bloqué en `Pending` avec une erreur `node(s) had volume node affinity conflict`.

**Comment l’éviter :** Toujours définir `volumeBindingMode: WaitForFirstConsumer` pour les Storage Classes qui seront utilisées dans les clusters multi-zones, ou utiliser un pilote CSI avec conscience topologique.

**Récupération :** Supprimez le PVC et recréez-le après avoir modifié le mode de liaison de la Storage Class, ou créez manuellement un PV dans la bonne zone et modifiez le PVC pour le lier.

### 2. Ignorer les conséquences de la politique de récupération

**Pourquoi cela arrive :** Les administrateurs définissent souvent `reclaimPolicy: Delete` par commodité sans réaliser que la suppression d’un PVC ou d’un namespace supprimera également le volume sous-jacent, entraînant potentiellement une perte de données. Inversement, `Retain` peut conduire à des volumes orphelins et des coûts inutiles si non nettoyés.

**Comment l’éviter :** Définissez explicitement la politique de récupération en fonction des besoins en données de la charge de travail. Utilisez `Retain` pour les applications stateful où les données doivent être préservées, et `Delete` uniquement pour les charges de travail éphémères ou facilement reproductibles. Documentez la politique dans la description de la Storage Class.

**Récupération :** Si `Delete` a été utilisé involontairement et que le volume est perdu, restaurez à partir des sauvegardes. Si `Retain` est utilisé et que des volumes sont orphelins, supprimez manuellement les volumes EBS après avoir confirmé qu’ils ne sont pas nécessaires.

### 3. Permissions IAM manquantes pour le provisionneur

**Pourquoi cela arrive :** Le gestionnaire de contrôleur ou le pilote CSI a besoin des permissions appropriées du fournisseur cloud pour créer, attacher et supprimer des volumes. Sans elles, le provisionnement échoue avec des erreurs `AccessDenied`.

**Comment l’éviter :** Assurez-vous que le rôle IAM associé à vos nœuds Kubernetes ou au pilote CSI dispose des permissions requises. Pour EBS intégré, le rôle d’instance de nœud a besoin de `ec2:CreateVolume`, `ec2:AttachVolume`, `ec2:DetachVolume`, etc. Pour CSI, utilisez les politiques recommandées.

**Récupération :** Vérifiez les journaux du contrôleur (`kubectl logs -n kube-system kube-controller-manager-...`) pour les erreurs de permission, corrigez la politique IAM, puis recréez le PVC.

### 4. Ne pas définir une Storage Class par défaut

**Pourquoi cela arrive :** Si aucune Storage Class par défaut n’est définie, les PVC sans `storageClassName` resteront indéfiniment non liés. Cela surprend souvent les nouveaux utilisateurs qui s’attendent à ce qu’une valeur par défaut existe.

**Comment l’éviter :** Désignez une Storage Class par défaut en utilisant l’annotation `storageclass.kubernetes.io/is-default-class`, ou spécifiez explicitement `storageClassName` dans chaque PVC.

**Récupération :** Ajoutez l’annotation à la Storage Class souhaitée, ou patchez le PVC pour inclure un `storageClassName` valide et recréez-le.

### 5. Surestimer les capacités d’expansion du stockage

**Pourquoi cela arrive :** Tous les provisionneurs ne prennent pas en charge l’expansion de volume, et même ceux qui le font peuvent nécessiter le drapeau `allowVolumeExpansion: true`. Tenter de redimensionner un PVC sur une Storage Class non compatible entraîne une erreur.

**Comment l’éviter :** Vérifiez que votre provisionneur prend en charge l’expansion et définissez `allowVolumeExpansion: true` seulement après avoir testé dans un environnement non productif. Pour EBS intégré, l’expansion n’est pas supportée ; vous devez utiliser le pilote CSI.

**Récupération :** Si l’expansion échoue, restaurez la taille d’origine du PVC et soit migrez les données vers un volume plus grand en utilisant un processus de sauvegarde/restauration, soit passez à un pilote CSI qui prend en charge l’expansion.

### 6. Oublier de nettoyer les ressources de test

**Pourquoi cela arrive :** Après les tests, les développeurs oublient souvent de supprimer les PVC et PV de test, laissant des ressources cloud orphelines qui engendrent des coûts.

**Comment l’éviter :** Mettez en place un script de nettoyage ou utilisez le ramasse-miettes Kubernetes avec des références propriétaires. Auditez régulièrement les volumes et leurs PVC associés.

**Récupération :** Supprimez manuellement le PVC et le PV, et vérifiez que le volume cloud sous-jacent est supprimé si la politique de récupération est `Delete`. Pour `Retain`, supprimez le volume cloud séparément.

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

Les échecs courants avec le provisionnement dynamique incluent :

- **Incompatibilité de zone :** Avec `volumeBindingMode: Immediate`, un PVC peut se lier à un volume dans une zone où aucun nœud n’existe, provoquant l’échec de planification du pod. Corrigez en utilisant `WaitForFirstConsumer` (comme nous l’avons fait) ou une planification consciente de la topologie avec CSI.
- **Permissions insuffisantes :** Le fournisseur cloud manque de permissions IAM pour créer des volumes. Vérifiez les journaux du contrôleur (`kubectl logs -n kube-system kube-controller-manager-...`) pour les erreurs `AccessDenied`. Corrigez le rôle IAM et réessayez.
- **Conflits de protection contre la suppression :** `reclaimPolicy: Retain` laisse des volumes après la suppression du PVC, nécessitant un nettoyage manuel. Si vous définissez `reclaimPolicy: Delete`, assurez-vous qu’aucun instantané ou dépendance ne bloque la suppression.
- **Quota fournisseur dépassé :** Le fournisseur cloud peut refuser de créer de nouveaux volumes si les limites sont atteintes. Augmentez le quota ou supprimez les volumes inutilisés.

Étapes de restauration et de récupération :

- Supprimez le pod qui utilise le PVC pour détacher le volume.
- Si le PVC est bloqué en `Pending` en raison d’une mauvaise configuration, supprimez-le et recréez-le après avoir corrigé la Storage Class.
- Pour une Storage Class corrompue, créez-en une nouvelle et patchez le champ `storageClassName` du PVC (nécessite que le PVC soit en état `Pending`).
- Si un volume ne se supprime pas, supprimez les finalisateurs ou supprimez manuellement via l’API cloud.

Exemple : forcer la suppression d’un PVC bloqué après avoir sauvegardé les données :

```bash
kubectl patch pvc -n storage-test test-pvc -p '{"metadata":{"finalizers":[]}}' --type=merge
kubectl delete pvc -n storage-test test-pvc
```

Vérifiez ensuite l’état du volume EBS dans AWS ; avec `Retain`, il reste disponible pour une récupération manuelle.

## Checklist opérationnelle

Utilisez les vérifications répétables suivantes pour les Storage Classes dans votre environnement. Attribuez un responsable unique pour chaque vérification majeure afin de garantir qu’elle soit effectuée. Revoyez la checklist mensuellement lors d’une réunion d’équipe pour adapter les fréquences et les commandes à votre environnement.

| Fréquence | Tâche | Commande / Outil | Résultat attendu | Responsable (Nom, Rôle) |
|-----------|------|------------------|-----------------|-------------------------|
| Quotidienne | Lister les Storage Classes et leur statut | `kubectl get storageclass` | Toutes les classes montrent les provisionneurs attendus et AGE | Priya Shah, Responsable Ingénierie |
| Quotidienne | Vérifier les PVC en échec | `kubectl get pvc --all-namespaces` | Aucun PVC bloqué en Pending pendant plus de 5 minutes | Tom Nguyen, Ingénieur DevOps |
| Hebdomadaire | Vérifier la Storage Class par défaut (si existante) | `kubectl get storageclass -o name` avec vérification d’annotation | Exactement une par défaut ou aucune comme prévu | Priya Shah, Responsable Ingénierie |
| Hebdomadaire | Examiner la conformité du chiffrement des volumes | Dépend du fournisseur ; ex. `aws ec2 describe-volumes` | Tous les volumes de production chiffrés | Tom Nguyen, Ingénieur DevOps |
| Mensuelle | Tester l’expansion de volume si activée | Appliquer une taille de PVC plus grande et vérifier le redimensionnement du PV | Le PVC montre la nouvelle taille sans redémarrage du pod (CSI uniquement) | Priya Shah, Responsable Ingénierie |
| Lors de changement | Valider le YAML de la Storage Class avant application | `kubectl apply --dry-run=client -f sc.yaml` | Aucune erreur de validation | Tom Nguyen, Ingénieur DevOps |
| Lors d’incident | Inspecter les événements pour PVC/PV | `kubectl describe pvc <name> -n <ns>` | Aucun événement d’avertissement | Ingénieur de garde |

Enregistrez ces vérifications dans le runbook de votre équipe et automatisez-les avec un cron job ou un système de surveillance. Utilisez une approche pilote étroite lors de l’introduction de nouveaux provisionneurs ou paramètres, en mesurant le succès avec une seule application avant une adoption plus large.

## Conclusion

Les Storage Classes Kubernetes abstraient le provisionnement du stockage, mais comprendre leur architecture est essentiel pour des opérations fiables. Nous avons parcouru une implémentation ciblée utilisant le provisionneur AWS EBS intégré avec chiffrement, vérifié le provisionnement dynamique et l’attachement, exploré les modes de défaillance courants avec des étapes de récupération, et fourni une checklist opérationnelle. Commencez avec une Storage Class pilote petite et mesurable, puis étendez en fonction du succès observé. Gardez vos définitions de Storage Class simples, utilisez `WaitForFirstConsumer` pour éviter les problèmes de zone, et testez toujours les procédures de restauration dans un environnement sûr avant la production.