## Introduction

La mise à niveau et la migration des volumes Kubernetes sont des opérations à haut risque. Une seule erreur peut empêcher les applications de démarrer, rendre les données inaccessibles ou laisser des ressources de stockage orphelines. Ce guide propose une approche pratique, basée sur des commandes, pour mettre à niveau et migrer des volumes dans un cluster Kubernetes, en mettant l'accent sur la sécurité, l'observabilité et la récupération.

Vous apprendrez à :

- Inventorier la configuration actuelle des volumes et des classes de stockage.
- Planifier et exécuter une migration de volume avec un minimum d'interruption.
- Mettre à niveau les provisionneurs de stockage ou les plugins de volume.
- Valider que les données sont intactes et que les applications sont saines.
- Revenir en arrière en cas de problème.

Chaque étape comprend de vraies commandes `kubectl`, des extraits de manifestes et les sorties attendues. L'objectif est de vous fournir un playbook reproductible qui réduit les risques et renforce la confiance.

Ce guide s'adresse aux développeurs, ingénieurs DevOps et équipes plateforme qui ont déjà une connaissance pratique des concepts fondamentaux de Kubernetes comme les Pods, les Deployments, les PersistentVolumes (PV), les PersistentVolumeClaims (PVC) et les StorageClasses. Si vous découvrez ces concepts, consultez la documentation officielle de Kubernetes avant de continuer.

Nous utiliserons une application e-commerce fictive appelée `shop-app` comme exemple. Elle se compose d'une base de données PostgreSQL (avec ses données sur un PersistentVolume) et d'un frontend web sans état. Toutes les commandes supposent que vous avez configuré `kubectl` avec accès à un cluster de test d'abord et que vous avez déjà sauvegardé les données critiques.

## Inventaire de la version et de l'environnement

Avant de toucher quoi que ce soit, vous devez savoir exactement ce que vous avez. Cette section explique comment rassembler un inventaire complet de votre configuration de stockage actuelle, y compris la version de Kubernetes, les StorageClasses, les PV et les PVC. Ces informations sont essentielles pour planifier une migration sûre et pour résoudre les problèmes éventuels.

### Vérifier la version de Kubernetes et les capacités de stockage

Commencez par vérifier la version de votre plan de contrôle et de vos nœuds Kubernetes. Certaines fonctionnalités de stockage, comme la migration CSI ou l'expansion de volume, dépendent de la version.

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

Exemple de sortie :

```text
Client Version: v1.27.3
Server Version: v1.27.3
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
node-1     Ready    control-plane   10d   v1.27.3   192.168.1.10   <none>        Ubuntu 22.04.2 LTS   5.15.0-76-generic   containerd://1.7.1
node-2     Ready    <none>          10d   v1.27.3   192.168.1.11   <none>        Ubuntu 22.04.2 LTS   5.15.0-76-generic   containerd://1.7.1
```

Notez la version du serveur. Si vous prévoyez de mettre à niveau des volumes qui dépendent d'un driver CSI spécifique, vérifiez la matrice de compatibilité de ce driver avec cette version.

### Lister les StorageClasses

Les StorageClasses définissent les types de stockage disponibles dans votre cluster. Vous devez savoir lesquelles sont utilisées et leurs provisionneurs.

```bash
kubectl get storageclass
```

Exemple de sortie :

```text
NAME                 PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   kubernetes.io/gce-pd    Delete          Immediate           false                  30d
fast                 kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer true                   30d
csi-example          example.csi.driver.io   Retain          Immediate           true                   20d
```

Notez le provisionneur (in-tree vs CSI), la politique de récupération et si l'expansion de volume est autorisée. Ces propriétés influencent les options de migration.

### Lister les PersistentVolumes et les Claims

Obtenez une vue détaillée de tous les PV et de leur statut de liaison.

```bash
kubectl get pv -o wide
```

Exemple de sortie :

```text
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                      STORAGECLASS   REASON   AGE
pvc-1234abcd-56ef-7890-1234-567890abcdef   10Gi       RWO            Delete           Bound    default/shop-db-data       standard                30d
pvc-5678efgh-90ij-1234-5678-901234ghijkl   5Gi        RWO            Delete           Bound    default/shop-db-backup     fast                    10d
```

Listez maintenant tous les PVC dans tous les namespaces :

```bash
kubectl get pvc --all-namespaces
```

Exemple de sortie :

```text
NAMESPACE   NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
default     shop-db-data     Bound    pvc-1234abcd-56ef-7890-1234-567890abcdef   10Gi       RWO            standard       30d
default     shop-db-backup   Bound    pvc-5678efgh-90ij-1234-5678-901234ghijkl   5Gi        RWO            fast           10d
```

### Identifier quels Pods utilisent quels volumes

Découvrez quels Pods en cours d'exécution montent ces PVC. Cela vous indique quelles charges de travail seront affectées par une migration.

```bash
kubectl get pods -o wide --all-namespaces
```

Ensuite, pour un Pod spécifique, décrivez-le pour voir les montages de volume :

```bash
kubectl describe pod shop-db-0 -n default
```

Recherchez les sections `Volumes` et `Mounts` dans la sortie. Vous pouvez aussi interroger directement avec JSONPath :

```bash
kubectl get pods -n default -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.volumes[*].persistentVolumeClaim.claimName}{"\n"}{end}'
```

Exemple de sortie :

```text
shop-db-0    shop-db-data
shop-web-xyz shop-web-uploads
```

Notez quels Pods utilisent chaque PVC. C'est essentiel pour planifier une fenêtre de maintenance et pour vérifier que les applications sont saines après la migration.

### Prérequis et vérification de compatibilité

Avant de procéder, assurez-vous d'avoir :

- Sauvegardes : Prenez un snapshot ou une sauvegarde de chaque volume que vous prévoyez de migrer. Pour les volumes cloud, utilisez la fonction de snapshot du fournisseur. Pour les environnements sur site, utilisez les outils de sauvegarde de votre système de stockage.
- Accès `kubectl` avec les permissions appropriées pour obtenir, créer et supprimer des PV, PVC et Pods.
- Capacité de stockage suffisante dans la classe de stockage cible pour contenir les données plus l'espace temporaire de migration.
- Un environnement de test qui reflète la production aussi fidèlement que possible.

Si vous mettez à niveau un driver CSI, consultez les notes de version du driver pour les versions de Kubernetes supportées et les chemins de mise à niveau. Certains drivers CSI peuvent être mis à niveau sur place, tandis que d'autres nécessitent une nouvelle instance du driver et une migration progressive des volumes.

## Chemin de configuration sécurisé

Une migration ou une mise à niveau sûre suit un chemin contrôlé : planifier, tester, sauvegarder, exécuter par étapes et valider à chaque étape. Cette section décrit un chemin sûr général, puis l'applique à un scénario concret de migration de volume d'un provisionneur in-tree vers un driver CSI.

### Chemin général de migration sécurisée

1. **Sauvegarde** : Prenez un instantané du volume source ou utilisez des sauvegardes au niveau applicatif.
2. **Test** : Effectuez la migration dans un namespace ou cluster non productif avec une configuration similaire.
3. **Planifier la bascule** : Décidez d'utiliser une approche blue/green (bleu/vert) ou canary. Pour les charges de travail avec état, un déploiement blue/green de l'application avec un nouveau volume est souvent plus simple.
4. **Exécuter** : Créez le nouveau volume, copiez les données, basculez l'application sur le nouveau volume et vérifiez.
5. **Nettoyer** : Supprimez l'ancien volume seulement après une période de validation réussie.

### Exemple : Migration d'un provisionneur in-tree vers un driver CSI

De nombreuses distributions Kubernetes déprécient les plugins de volume in-tree au profit des drivers CSI. Une migration courante est celle du provisionneur in-tree `kubernetes.io/gce-pd` vers le driver CSI GCE PD. Le processus implique la création d'une nouvelle StorageClass, la migration des PV et des tests.

**Étape 1 : Installer le driver CSI** (s'il n'est pas déjà installé). Pour GCE PD, vous pouvez appliquer les manifestes du driver depuis le dépôt officiel. Vérifiez que les pods du driver fonctionnent :

```bash
kubectl get pods -n kube-system | grep csi
```

Sortie attendue (similaire) :

```text
gce-pd-csi-driver-controller-0   4/4     Running   0          5m
gce-pd-csi-driver-node-xxxxx     2/2     Running   0          5m
```

**Étape 2 : Créer une nouvelle StorageClass** utilisant le provisionneur CSI. Enregistrez le YAML suivant sous `csi-standard.yaml` :

```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-standard
provisioner: pd.csi.storage.gke.io
parameters:
  type: pd-standard
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
```

Appliquez-le :

```bash
kubectl apply -f csi-standard.yaml
```

Vérifiez :

```bash
kubectl get storageclass csi-standard
```

**Étape 3 : Migrer un volume existant**. La méthode recommandée est de créer un nouveau PVC avec la nouvelle StorageClass et de copier les données. Nous utiliserons une méthode simple avec `kubectl cp` pour des volumes de taille modérée. Pour des volumes très volumineux, envisagez d'utiliser un job avec `rsync` ou un outil comme Velero.

D'abord, créez un nouveau PVC pour les données de la base de données :

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shop-db-data-csi
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: csi-standard
  resources:
    requests:
      storage: 10Gi
```

Appliquez et attendez qu'il soit lié :

```bash
kubectl apply -f shop-db-data-csi.yaml
kubectl get pvc shop-db-data-csi
```

Vous verrez le STATUT devenir `Bound` une fois qu'un PV est provisionné.

Ensuite, vous avez besoin d'un Pod temporaire pour copier les données. Comme la base de données est en cours d'exécution, vous devez arrêter les écritures pour garantir la cohérence. Pour une migration en production, vous arrêteriez l'application ou utiliseriez une méthode de réplication de base de données. Pour cet exemple, nous supposerons que vous pouvez temporairement réduire le StatefulSet de la base de données à zéro.

Réduisez la base de données :

```bash
kubectl scale statefulset shop-db --replicas=0
```

Créez un Pod temporaire qui monte à la fois l'ancien et le nouveau PVC :

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: data-migrator
spec:
  containers:
  - name: migrator
    image: busybox
    command: ["/bin/sh", "-c"]
    args:
      - |
        echo "Copie des données..."
        cp -a /source/* /destination/
        echo "Copie terminée"
        sleep 3600
    volumeMounts:
    - name: source
      mountPath: /source
    - name: destination
      mountPath: /destination
  volumes:
  - name: source
    persistentVolumeClaim:
      claimName: shop-db-data
  - name: destination
    persistentVolumeClaim:
      claimName: shop-db-data-csi
  restartPolicy: Never
```

Appliquez et attendez la fin de la copie :

```bash
kubectl apply -f data-migrator.yaml
kubectl logs data-migrator
```

Sortie attendue :

```text
Copie des données...
Copie terminée
```

Une fois la copie terminée, supprimez le Pod migrateur.

**Étape 4 : Mettre à jour l'application pour utiliser le nouveau PVC**. Pour un StatefulSet, vous mettriez à jour les `volumeClaimTemplates`. Cependant, comme les PersistentVolumeClaims créés à partir de modèles sont immuables, vous ne pouvez pas simplement changer le `storageClassName`. L'approche courante consiste à créer un nouveau StatefulSet avec un nom différent, ou à utiliser un outil comme `kubectl patch` si le PVC le permet. Pour simplifier, nous supposerons ici que la base de données est un Pod unique géré par un Deployment.

S'il s'agissait d'un Deployment, vous pourriez corriger le nom du claim de volume :

```bash
kubectl patch deployment shop-db --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/volumes/0/persistentVolumeClaim/claimName", "value": "shop-db-data-csi"}]'
```

Puis remontez à l'échelle :

```bash
kubectl scale deployment shop-db --replicas=1
```

**Étape 5 : Vérifier** que l'application fonctionne et que les données sont intactes. Consultez les journaux et exécutez une requête.

```bash
kubectl logs deployment/shop-db --tail=20
kubectl exec -it deployment/shop-db -- psql -U postgres -c "SELECT count(*) FROM orders;"
```

Sortie attendue (exemple) :

```text
 count 
-------
  1234
(1 row)
```

Si tout fonctionne, vous pouvez supprimer l'ancien PVC après une certaine période de surveillance.

## Vérification et diagnostics

Après toute migration ou mise à niveau, vous devez vérifier que le système fonctionne correctement. Cette section fournit des commandes et des techniques pour diagnostiquer les problèmes de stockage et confirmer l'intégrité des données.

### Vérifier la liaison des volumes et leur statut

Vérifiez que les PVC sont liés et que les PV sont dans l'état attendu.

```bash
kubectl get pvc -n default
kubectl get pv
```

Pour un PVC spécifique, décrivez-le pour voir les événements et les détails de liaison :

```bash
kubectl describe pvc shop-db-data-csi
```

Recherchez des avertissements tels que `FailedBinding` ou `ProvisioningFailed`. Ils indiquent des problèmes avec le provisionneur de stockage ou la capacité.

### Vérifier la santé des Pods et les montages de volume

Assurez-vous que le Pod fonctionne et que le volume est monté correctement.

```bash
kubectl get pods
kubectl describe pod shop-db-xxxxx
```

Dans la sortie de description, sous `Volumes`, vous devriez voir le nom du PVC et le chemin de montage. Sous `Conditions`, `Ready` devrait être `True`. Si le Pod est bloqué dans `ContainerCreating`, vérifiez les événements pour des erreurs liées au volume.

Erreurs courantes :

- `FailedMount` : Le volume n'a pas pu être monté en raison de problèmes de périphérique manquant ou d'autorisations.
- `FailedAttachVolume` : Le nœud n'a pas pu attacher le volume, souvent à cause d'une discordance de zone ou de problèmes de driver.

Utilisez `kubectl logs` pour voir les journaux d'application qui pourraient indiquer des problèmes de lecture/écriture de données.

### Tester les performances en lecture/écriture

Pour vous assurer que le nouveau volume offre des performances adéquates, vous pouvez exécuter un test simple d'E/S à l'intérieur du Pod. Par exemple, si le Pod a un shell, écrivez et lisez un fichier de test :

```bash
kubectl exec -it deployment/shop-db -- bash
# Dans le conteneur
dd if=/dev/zero of=/var/lib/postgresql/data/testfile bs=1M count=100
dd if=/var/lib/postgresql/data/testfile of=/dev/null bs=1M count=100
rm /var/lib/postgresql/data/testfile
```

Cela écrit un fichier de 100 Mo et le relit. Vérifiez s'il y a des erreurs ou des performances anormalement lentes.

### Valider la cohérence du système de fichiers

Pour les volumes de base de données, utilisez les contrôles de cohérence intégrés de la base de données. Pour PostgreSQL, vous pouvez exécuter `pg_dump` vers un fichier temporaire ou utiliser `psql` pour exécuter quelques requêtes. Pour d'autres applications, comparez le nombre de fichiers ou les sommes de contrôle avant et après la migration.

Si vous avez une sauvegarde, vous pouvez comparer le nombre de fichiers ou la taille totale :

```bash
kubectl exec -it deployment/shop-db -- du -sh /var/lib/postgresql/data
```

Comparez cela au volume source avant la suppression.

### Surveiller les métriques de stockage

Si votre cluster dispose d'une surveillance (Prometheus, Grafana), examinez les métriques liées au volume telles que `kubelet_volume_stats_used_bytes`, `kubelet_volume_stats_capacity_bytes` et les erreurs d'opération de volume. Configurez des alertes en cas d'espace disque faible ou de latence élevée.

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

Même avec une planification minutieuse, des défaillances peuvent survenir. Cette section décrit les scénarios de défaillance courants lors de la migration et de la mise à niveau des volumes, ainsi que les étapes de récupération.

### Capacité insuffisante dans la nouvelle StorageClass

Défaillance : Le nouveau PVC reste à l'état `Pending` car le provisionneur de stockage ne peut pas créer un volume de la taille demandée (par exemple, la classe de stockage a une limite ou le backend est à court d'espace).

Diagnostic :

```bash
kubectl describe pvc shop-db-data-csi
```

Recherchez des événements comme :

```text
Warning  ProvisioningFailed  2m (x5 over 5m)  persistentvolume-controller  failed to provision volume with StorageClass "csi-standard": rpc error: code = ResourceExhausted desc = Insufficient capacity
```

Récupération :

- Vérifiez la capacité disponible dans votre backend de stockage.
- Réduisez la taille demandée si possible (mais seulement si les données y tiennent).
- Utilisez une autre StorageClass avec plus de capacité.

### Copie de données incomplète ou corrompue

Défaillance : Le Pod migrateur de données se termine avec le code de sortie 0 mais l'application ne démarre pas ou des données sont manquantes.

Diagnostic :

- Comparez la taille des volumes source et destination en utilisant `du -sh`.
- Vérifiez les journaux du Pod migrateur pour des erreurs qui auraient pu être ignorées.
- Exécutez des contrôles d'intégrité au niveau applicatif (par exemple, cohérence de la base de données).

Récupération :

- Si une corruption est suspectée, ne supprimez pas le volume source. Relancez la copie avec une méthode plus fiable (par exemple, `rsync` avec vérification par somme de contrôle).
- Pour les bases de données, envisagez d'utiliser la sauvegarde/restauration native au lieu de la copie de fichiers.

### Le Pod ne parvient pas à monter le nouveau volume

Défaillance : Après avoir basculé le PVC, le Pod est bloqué dans `ContainerCreating` avec des événements `FailedMount`.

Diagnostic :

```bash
kubectl describe pod shop-db-xxxxx
```

Recherchez des erreurs de montage :

```text
Warning  FailedMount  2m   kubelet  MountVolume.MountDevice failed for volume "pvc-..." : driver name pd.csi.storage.gke.io not found in the list of registered CSI drivers
```

Récupération :

- Assurez-vous que le driver CSI est installé et fonctionne sur le nœud.
- Vérifiez que la StorageClass référence le bon provisionneur.
- Si le volume a été créé par un driver différent, vous devrez peut-être définir manuellement le champ `csi.driver` du PV et redémarrer le kubelet.

### Stratégie de rollback

Si la migration échoue et que vous ne pouvez pas résoudre le problème rapidement, revenez au volume d'origine.

Étapes :

1. Réduisez l'application à zéro.
2. Revenez à l'ancien nom de PVC dans la référence du Pod ou du StatefulSet.
3. Remontez l'application à l'échelle.
4. Vérifiez que l'ancien volume est toujours intact et que l'application fonctionne.
5. Enquêtez sur l'échec avant de réessayer.

Conservez toujours l'ancien volume jusqu'à ce que vous soyez sûr que la nouvelle configuration est stable. Fixez une période de surveillance (par exemple, une semaine) avant de supprimer l'ancien PVC.

### Échec de la mise à niveau du driver CSI

Si vous mettez à niveau le driver CSI lui-même et que la nouvelle version ne démarre pas, vous pouvez revenir à la version précédente du driver en réappliquant les anciens manifestes ou en utilisant une méthode de déploiement versionnée (par exemple, Helm rollback).

```bash
helm rollback my-csi-driver 1
```

Vérifiez ensuite que les pods du driver sont sains :

```bash
kubectl get pods -n kube-system | grep csi
```

## Liste de contrôle opérationnelle

Utilisez cette liste de contrôle avant, pendant et après une migration ou une mise à niveau de volume pour vous assurer que rien n'est oublié.

### Pré-migration

- [ ] Sauvegarder toutes les données critiques des volumes à migrer.
- [ ] Vérifier que les sauvegardes sont restaurables en effectuant une restauration de test.
- [ ] Enregistrer la version actuelle de Kubernetes, les StorageClasses, les PV, les PVC et les correspondances Pod-volume.
- [ ] Identifier toutes les applications utilisant les volumes et leur tolérance aux interruptions.
- [ ] Vérifier la capacité du système de stockage cible.
- [ ] Tester le processus de migration dans un environnement de staging.
- [ ] Planifier une fenêtre de maintenance et informer les parties prenantes.

### Pendant la migration

- [ ] Réduire les applications qui écrivent sur les volumes sources (ou arrêter les écritures).
- [ ] Créer de nouveaux PVC avec la StorageClass cible.
- [ ] Démarrer le job de copie des données et surveiller la progression.
- [ ] Vérifier que la copie des données s'est terminée avec succès (taille, sommes de contrôle si possible).
- [ ] Mettre à jour les manifestes des applications pour utiliser les nouveaux PVC.
- [ ] Remonter les applications à l'échelle.
- [ ] Exécuter des tests de fumée et des vérifications au niveau applicatif.

### Post-migration

- [ ] Vérifier la santé des Pods et les montages de volume (`kubectl get pods`, `kubectl describe pod`).
- [ ] Consulter les journaux d'application pour détecter des erreurs.
- [ ] Exécuter des contrôles d'intégrité de la base de données ou équivalent.
- [ ] Surveiller les métriques de performance pendant une période définie.
- [ ] Conserver les anciens volumes pour le rollback jusqu'à la fin de la période de validation.
- [ ] Supprimer les anciens volumes et nettoyer les ressources temporaires.
- [ ] Documenter la nouvelle configuration et mettre à jour les procédures.

### Liste de contrôle de rollback d'urgence

- [ ] Réduire les applications affectées à zéro.
- [ ] Revenir aux anciennes références de PVC.
- [ ] Remonter les applications à l'échelle.
- [ ] Vérifier que les anciens volumes sont intacts et que les applications fonctionnent.
- [ ] Enquêter sur la cause racine avant de réessayer.

## Conclusion

La mise à niveau et la migration des volumes Kubernetes exigent une planification et une exécution minutieuses. En suivant l'approche structurée de ce guide, vous pouvez minimiser les risques de temps d'arrêt et de perte de données. Les principes clés sont :

- **Inventorier d'abord** : Connaître la disposition actuelle du stockage et les dépendances.
- **Tout sauvegarder** : Ne jamais migrer sans une sauvegarde vérifiée.
- **Tester en staging** : Répéter la migration avant la production.
- **Aller étape par étape** : Utiliser un chemin sûr avec des points de rollback.
- **Vérifier rigoureusement** : Utiliser des commandes et des contrôles pour confirmer l'intégrité des données et la santé des applications.
- **Garder le rollback prêt** : Conserver les anciens volumes jusqu'à ce que le nouveau système se révèle stable.

Avec ces pratiques, vous pouvez traiter les migrations et mises à niveau de volumes comme des opérations de routine plutôt que comme des événements à haut risque. Commencez par un volume à faible risque, documentez votre processus et affinez-le au fil du temps. Les exemples de commandes et les listes de contrôle de cet article fournissent une base solide pour construire votre propre playbook adapté à votre environnement.