## Introduction Les plugins de périphériques Kubernetes comblent le fossé entre le matériel spécialisé et vos charges de travail. Ils annoncent des ressources telles que les GPU, FPGA, cartes réseau ou capacités RDMA au kubelet, qui planifie ensuite les pods nécessitant ces ressources. Automa­tiser leur déploiement et leur cycle de vie via CI/CD est un défi en raison de leur couplage étroit avec le matériel des nœuds, les pilotes du noyau et les versions du cluster. Cet article propose une approche pratique, étape par étape, pour intégrer les plugins de périphériques dans votre pipeline CI/CD, en garantissant des déploiements sûrs, une vérification immédiate et une annulation fiable. Nous nous concentrons sur les plugins de périphériques courants comme NVIDIA GPU, Intel FPGA et les plugins d'exemple génériques, en montrant comment observer l'état du cluster, appliquer les modifications de manière contrôlée et vérifier le fonctionnement. Que vous soyez sur site ou dans des instances GPU cloud, les principes restent les mêmes. À la fin, vous disposerez d'un flux de travail concret : de l'inventaire des versions au déploiement automatisé, en passant par les contrôles de santé, la détection des échecs et les stratégies de retour en arrière, le tout appuyé par des exemples en ligne de commande et des extraits de configuration. ## Inventaire des versions et de l'environnement Avant d'automatiser quoi que ce soit, vous devez connaître votre état actuel. Les plugins de périphériques sont sensibles aux versions : une incompatibilité entre le plugin, l'API Kubernetes, le moteur d'exécution des conteneurs et les pilotes matériels peut provoquer des échecs silencieux. Commencez par recueillir des informations en lecture seule sur votre cluster et vos nœuds. Commencez par les détails au niveau du cluster : ```bash kubectl version --short kubectl get nodes -o wide kubectl get pods -n kube-system -l app.kubernetes.io/component=device-plugin ``` Exemple de sortie attendue : ``` 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 gpu-node1 Ready 30d v1.27.3 10.10.0.4 Ubuntu 22.04.3 LTS 5.15.0-91-generic containerd://1.7.2 gpu-node2 Ready 30d v1.27.3 10.10.0.5 Ubuntu 22.04.3 LTS 5.15.0-91-generic containerd://1.7.2 ``` Pour chaque nœud hébergeant des plugins de périphériques, vérifiez la configuration du kubelet et le répertoire des plugins de périphériques : ```bash kubectl describe node gpu-node1 | grep -A5 "Capacity:" ls -la /var/lib/kubelet/device-plugins/ # sur le nœud ``` Le chemin d'enregistrement des plugins de périphériques du kubelet est par défaut `/var/lib/kubelet/device-plugins/`, mais il peut varier. Vérifiez le drapeau `--device-plugin-enabled` et les ressources enregistrées : ```bash kubectl describe node gpu-node1 | grep -A20 "Allocated resources:" ``` Pour les GPU NVIDIA, confirmez les versions du pilote et du moteur d'exécution : ```bash # Sur le nœud nvidia-smi nvidia-container-cli info ``` Exemple de sortie : ``` +-----------------------------------------------------------------------------+ | NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 | |-------------------------------+----------------------+----------------------+ ... ``` Vérifiez si le daemonset du plugin de périphériques est déjà en cours d'exécution : ```bash kubectl get ds -n kube-system | grep nvidia kubectl get pods -n kube-system -l name=nvidia-device-plugin-ds ``` Consignez toutes vos découvertes dans votre feuille d'inventaire. Cette étape d'observation protège contre les mises à niveau incompatibles. ## Chemin de configuration sécurisé La façon la plus sûre d'introduire des changements est progressive : d'abord dans un environnement de préproduction, puis sur un nœud canari, et enfin un déploiement sur tous les nœuds. Les plugins de périphériques s'exécutent en tant que DaemonSets, donc les changements affectent tous les nœuds correspondants. Contrôlez cela via des sélecteurs de nœuds et des tolérances. Les manifestes courants des plugins de périphériques incluent un DaemonSet avec un montage hostPath pour `/var/lib/kubelet/device-plugins`. Voici un exemple minimal pour le plugin de périphériques NVIDIA : ```yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: nvidia-device-plugin-daemonset namespace: kube-system spec: selector: matchLabels: name: nvidia-device-plugin-ds template: metadata: labels: name: nvidia-device-plugin-ds spec: priorityClassName: system-node-critical tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule containers: - name: nvidia-device-plugin-ctr image: nvcr.io/nvidia/k8s-device-plugin:v0.14.3 env: - name: FAIL_ON_INIT_ERROR value: "false" securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] volumeMounts: - name: device-plugin mountPath: /var/lib/kubelet/device-plugins volumes: - name: device-plugin hostPath: path: /var/lib/kubelet/device-plugins ``` Tout d'abord, déployez Node Feature Discovery (NFD) pour étiqueter automatiquement les nœuds compatibles GPU. NFD découvre les caractéristiques matérielles et applique des étiquettes telles que `feature.node.kubernetes.io/pci-10de.present=true` aux nœuds dotés de GPU NVIDIA, éliminant ainsi le besoin de commandes `kubectl label` manuelles. ```bash kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/node-feature-discovery/master/deployment/base/nfd.yaml kubectl get nodes -l feature.node.kubernetes.io/pci-10de.present=true ``` Pour appliquer le plugin de périphériques à un seul nœud canari, modifiez le DaemonSet pour cibler ce nœud par nom d'hôte : ```bash kubectl patch ds nvidia-device-plugin-daemonset -n kube-system -p '{"spec":{"template":{"spec":{"nodeSelector":{"kubernetes.io/hostname":"gpu-node1"}}}}}' ``` Vérifiez que le plugin s'enregistre uniquement sur ce nœud : ```bash kubectl describe node gpu-node1 | grep nvidia.com/gpu ``` Sortie attendue : ``` nvidia.com/gpu: 1 nvidia.com/gpu: 1 ``` Si cela réussit, promouvez vers tous les nœuds GPU en modifiant le sélecteur de nœuds du DaemonSet pour utiliser l'étiquette générée par NFD : ```bash kubectl patch ds nvidia-device-plugin-daemonset -n kube-system -p '{"spec":{"template":{"spec":{"nodeSelector":{"feature.node.kubernetes.io/pci-10de.present":"true"}}}}}' ``` Gardez les ensembles de modifications petits et réversibles. ## Vérification et diagnostic Après le déploiement, vérifiez non seulement que les pods sont en cours d'exécution, mais aussi que le plugin a annoncé correctement les ressources et que les charges de travail peuvent les consommer. Tout d'abord, confirmez que les pods du daemonset sont sains : ```bash kubectl get pods -n kube-system -l name=nvidia-device-plugin-ds -o wide kubectl rollout status ds/nvidia-device-plugin-daemonset -n kube-system ``` Consultez les journaux pour vérifier le succès de l'enregistrement : ```bash kubectl logs -n kube-system -l name=nvidia-device-plugin-ds --tail=50 ``` Recherchez des lignes comme : ``` I0912 10:00:01.234567 1 main.go:154] Starting FS watcher. I0912 10:00:01.234567 1 main.go:161] Starting OS watcher. I0912 10:00:01.234567 1 main.go:176] Starting to serve on /var/lib/kubelet/device-plugins/nvidia-gpu.sock I0912 10:00:01.234567 1 main.go:183] Registered device plugin with Kubelet ``` Pour tester l'allocation réelle des ressources, créez un pod demandant un GPU : ```yaml apiVersion: v1 kind: Pod metadata: name: gpu-test spec: restartPolicy: Never containers: - name: cuda-vector-add image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda11.7.1-ubi8 resources: limits: nvidia.com/gpu: 1 ``` Appliquez et vérifiez les journaux : ```bash kubectl apply -f gpu-test.yaml kubectl logs gpu-test ``` Sortie attendue : ``` [Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory Test PASSED Done ``` Si le pod ne parvient pas à être planifié, inspectez les événements : ```bash kubectl describe pod gpu-test | grep -A10 Events ``` Surveillez les messages comme : ``` 0/2 nodes are available: 2 Insufficient nvidia.com/gpu. ``` Cela indique que le plugin n'a pas enregistré les ressources ou que le sélecteur de nœuds a exclu tous les nœuds. ## Modes de défaillance et récupération Les défaillances des plugins de périphériques peuvent être subtiles. Les scénarios courants incluent : 1. **Socket d'enregistrement non créé** : Le conteneur du plugin s'exécute mais ne peut pas créer le socket Unix en raison de problèmes de permissions ou d'un mauvais chemin de montage. Diagnostic : ```bash kubectl logs -n kube-system -l name=nvidia-device-plugin-ds | grep -i error ``` Exemple d'erreur : ``` E0912 10:05:00.000000 1 main.go:123] failed to create device plugin socket: mkdir /var/lib/kubelet/device-plugins: permission denied ``` Récupération : Assurez-vous que le conteneur s'exécute en tant que root ou avec un contexte de sécurité approprié, et que le répertoire hostPath a les bonnes permissions (généralement 0755). 2. **Le redémarrage du kubelet déconnecte les plugins** : Lorsque le kubelet redémarre, les plugins doivent se réenregistrer. Si le plugin ne gère pas la reconnexion, les ressources disparaissent jusqu'au redémarrage du pod. Diagnostic : ```bash kubectl get node gpu-node1 -o json | jq '.status.capacity' ``` Comparez la capacité avant et après le redémarrage du kubelet. Si `nvidia.com/gpu` est absent, le plugin peut ne pas s'être réenregistré. Récupération : Redémarrez le daemonset du plugin. ```bash kubectl rollout restart ds/nvidia-device-plugin-daemonset -n kube-system ``` 3. **La mise à jour du pilote ou du runtime casse la compatibilité** : Après une mise à jour du noyau ou du pilote d'un nœud, le plugin peut échouer à s'initialiser. Diagnostic : Vérifiez les journaux du plugin pour les messages `FAIL_ON_INIT_ERROR`. Si vous avez défini `FAIL_ON_INIT_ERROR: false`, le plugin peut s'exécuter mais ne pas s'enregistrer. Réglez-le sur `true` pour planter et rendre l'échec visible. Récupération : Revenez en arrière sur le pilote ou mettez à jour le plugin vers une version compatible. 4. **Fuite de ressources ou socket obsolète** : D'anciens sockets de plugins de périphériques peuvent persister et perturber le kubelet. Diagnostic : ```bash ls -la /var/lib/kubelet/device-plugins/ ``` Si vous voyez des sockets en double ou obsolètes, nettoyez-les manuellement après avoir arrêté le plugin. Récupération : ```bash systemctl stop kubelet rm -f /var/lib/kubelet/device-plugins/*.sock systemctl start kubelet kubectl delete pod -n kube-system -l name=nvidia-device-plugin-ds ``` Pour les retours en arrière dans un contexte CI/CD, maintenez des manifestes versionnés et utilisez `kubectl apply` avec la version précédente. Par exemple, si vous êtes passé de v0.14.2 à v0.14.3 et rencontrez des problèmes, revenez en arrière : ```bash kubectl set image ds/nvidia-device-plugin-daemonset -n kube-system nvidia-device-plugin-ctr=nvcr.io/nvidia/k8s-device-plugin:v0.14.2 ``` Surveillez l'état de la mise à jour progressive : ```bash kubectl rollout status ds/nvidia-device-plugin-daemonset -n kube-system ``` ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle avant et après l'application de modifications aux plugins de périphériques en production. Attribuez un responsable unique pour chaque étape et précisez la fréquence de révision. | # | Action | Commande / Vérification | Responsable | Fréquence | |---|--------|-------------------------|-------------|-----------| | 1 | Vérifier la compatibilité matérielle et des pilotes des nœuds | Exécutez `nvidia-smi` sur tous les nœuds cibles et comparez avec la matrice de prise en charge du plugin | Responsable Infrastructure (ex. Priya Shah) | Avant chaque déploiement | | 2 | Appliquer le manifeste du plugin sur le nœud canari | `kubectl apply -f nvidia-device-plugin-canary.yaml` (avec sélecteur de nœud) | Ingénieur DevOps (ex. Alex Chen) | À chaque déploiement | | 3 | Valider l'enregistrement du plugin | `kubectl describe node | grep nvidia.com/gpu` | Ingénieur DevOps | À chaque déploiement | | 4 | Exécuter un pod de test GPU | `kubectl apply -f gpu-test.yaml && kubectl logs gpu-test` | Responsable QA (ex. Maria Gomez) | À chaque déploiement | | 5 | Promouvoir vers tous les nœuds | Modifier le sélecteur de nœuds du DaemonSet pour correspondre à tous les nœuds GPU | Ingénieur DevOps | Après vérification du canari | | 6 | Surveiller la capacité des nœuds et la planification des pods | `kubectl get nodes -o custom-columns=NAME:.metadata.name,GPU:.status.capacity.nvidia\.com/gpu` | SRE (ex. John Lee) | Quotidiennement la première semaine | | 7 | Vérifier les sockets fuites ou les processus obsolètes | `ls -la /var/lib/kubelet/device-plugins/` sur les nœuds | Administrateur de nœuds (ex. Sam Patel) | Hebdomadaire | | 8 | Examiner la version du plugin et les CVE connues | Consulter les notes de version du fournisseur et les bases de données CVE | Responsable Sécurité (ex. Emily Brown) | Mensuel | Chaque élément doit être journalisé dans votre système CI/CD avec un horodatage et un résultat. Si un contrôle échoue, arrêtez le pipeline et déclenchez la procédure de retour en arrière. ## Pièges courants et comment les éviter Malgré tous les efforts, des erreurs surviennent. Voici les pièges fréquents dans l'automatisation des plugins de périphériques : ### Ignorer l'hétérogénéité des nœuds **Pourquoi cela arrive** : Tous les nœuds n'ont pas le même matériel ou les mêmes pilotes. Appliquer un plugin uniformément peut provoquer des échecs sur des nœuds incompatibles. **Comment l'éviter** : Utilisez les étiquettes découvertes par NFD et les sélecteurs de nœuds pour cibler uniquement les nœuds dotés du matériel spécifique. Maintenez des DaemonSets distincts pour différents types de matériel si nécessaire. **Récupération** : Si un plugin plante sur un nœud, isolez-le en le cordonnant et en supprimant le pod du plugin. Exemple : ```bash kubectl cordon gpu-node2 kubectl delete pod -n kube-system -l name=nvidia-device-plugin-ds --field-selector spec.nodeName=gpu-node2 ``` Ensuite, corrigez le pilote ou remplacez le matériel. ### Mauvaise configuration des chemins de montage **Pourquoi cela arrive** : Des configurations kubelet personnalisées peuvent utiliser un répertoire de plugins de périphériques différent. Le défaut est `/var/lib/kubelet/device-plugins`, mais certains clusters utilisent `/var/lib/kubelet/device-plugins/kubelet.sock` ou un chemin personnalisé. **Comment l'éviter** : Vérifiez les drapeaux du kubelet sur les nœuds : ```bash ps aux | grep kubelet | grep device-plugins ``` Recherchez `--device-plugin-path` ou similaire. Assurez-vous que les montages de votre DaemonSet correspondent. **Récupération** : Mettez à jour le montage du volume du DaemonSet vers le bon chemin et redémarrez les pods. ### Ne pas gérer les temps d'arrêt du plugin **Pourquoi cela arrive** : Les mises à jour progressives des plugins de périphériques peuvent brièvement supprimer des ressources des nœuds, provoquant des pods en attente. Si les charges de travail sont sensibles, cela peut entraîner des perturbations. **Comment l'éviter** : Utilisez `maxUnavailable: 0` dans la stratégie de mise à jour du DaemonSet (si pris en charge) ou effectuez les mises à jour pendant les fenêtres de maintenance. Pour les charges de travail critiques, envisagez de drainer le nœud avant la mise à jour du plugin. **Récupération** : Si des pods restent bloqués, redémarrez-les une fois le plugin sain. ### Négliger les contextes de sécurité **Pourquoi cela arrive** : Les plugins de périphériques ont souvent besoin d'un accès privilégié ou de capacités spécifiques. Exécuter avec trop de permissions est risqué, mais trop restrictif peut casser l'enregistrement. **Comment l'éviter** : Suivez le principe du moindre privilège. Pour le plugin NVIDIA, supprimez toutes les capacités et définissez `allowPrivilegeEscalation: false` comme indiqué précédemment. Évitez d'exécuter en tant que root si possible, mais certains plugins l'exigent. **Récupération** : Si le plugin échoue en raison du contexte de sécurité, ajustez et redéployez, puis testez avec un pod GPU. ## Conclusion L'automatisation des plugins de périphériques Kubernetes dans le CI/CD exige une observation minutieuse, des changements contrôlés et une vérification rigoureuse. En suivant l'approche structurée décrite — de l'inventaire et de la configuration sécurisée aux diagnostics et au retour en arrière — vous pouvez réduire les temps d'arrêt et garantir que les ressources matérielles sont disponibles de manière fiable pour vos charges de travail. Commencez par mettre en œuvre la liste de contrôle opérationnelle dans votre pipeline pour la prochaine mise à jour du plugin de périphériques. Attribuez des responsables, exécutez le déploiement canari et vérifiez avec une charge de travail d'exemple. Au fil du temps, vous gagnerez en confiance et détecterez les problèmes avant qu'ils n'affectent la production. N'oubliez pas : les plugins de périphériques sont un pont critique entre le matériel et Kubernetes. Traitez leur cycle de vie avec la même rigueur que tout autre composant d'infrastructure.