## Introduction La mise à niveau ou la migration de Kubernetes Topology Manager ne se résume pas à changer un numéro de version. Il s’agit d’un changement opérationnel qui peut modifier la façon dont le kubelet aligne les ressources CPU, mémoire et périphériques entre les nœuds NUMA. Une mise à niveau négligente peut entraîner des échecs d’admission des pods, un alignement inattendu des ressources, voire une instabilité du nœud. Ce guide fournit une approche pratique et concrète pour les opérateurs, les ingénieurs DevOps et les équipes plateforme qui doivent planifier, exécuter, vérifier et récupérer après des modifications de Topology Manager. Nous suivrons un flux de travail complet : inventorier l’environnement actuel, concevoir un chemin de configuration sûr, valider les modifications avant le déploiement, diagnostiquer les échecs et effectuer une restauration si nécessaire. Chaque section comprend des commandes concrètes, des sorties attendues réalistes et des critères de décision. Les exemples supposent un cluster Kubernetes exécutant la version 1.27 ou ultérieure, mais les principes s’appliquent à toute version prise en charge. L’objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d’impact, utiliser des espaces réservés au lieu de secrets, vérifier le résultat et documenter la procédure de récupération si l’état attendu n’est pas atteint. ## Inventaire des versions et de l’environnement Avant de toucher à toute configuration, vous devez savoir exactement ce que vous exécutez. Cette section couvre la collecte des informations nécessaires sur votre version de Kubernetes, la topologie des nœuds, la configuration actuelle de Topology Manager et les composants pertinents. ### 1. Identifier les versions de Kubernetes et du kubelet Exécutez la commande suivante sur un nœud du plan de contrôle : ```bash kubectl version --short ``` Depuis Kubernetes 1.26, l’option `--short` est dépréciée mais reste largement utilisée. Une sortie typique ressemble à : ``` Client Version: v1.27.3 Kustomize Version: v5.0.1 Server Version: v1.27.3 ``` Sur chaque nœud worker, vérifiez la version du kubelet : ```bash kubelet --version ``` Exemple de sortie : ``` Kubernetes v1.27.3 ``` Enregistrez à la fois les versions du plan de contrôle et du kubelet. Le comportement de Topology Manager peut différer selon les versions du kubelet, même si le plan de contrôle est identique. ### 2. Vérifier la configuration actuelle de Topology Manager Le fichier de configuration du kubelet se trouve généralement dans `/var/lib/kubelet/config.yaml`. Inspectez-le pour les champs liés à la topologie : ```bash sudo cat /var/lib/kubelet/config.yaml | grep -A 20 topologyManager ``` Si Topology Manager n’est pas configuré, vous ne verrez aucune sortie ou les valeurs par défaut suivantes : ```yaml topologyManagerPolicy: none ``` Les autres valeurs possibles sont : - `none` : Topology Manager désactivé (par défaut) - `best-effort` : aligne les ressources lorsque possible, mais ne rejette jamais les pods - `restricted` : aligne strictement les ressources, rejette les pods qui ne peuvent pas être alignés - `single-numa-node` : identique à `restricted`, mais exige en plus que toutes les ressources tiennent sur un seul nœud NUMA (déprécié en 1.27, utilisez `restricted` avec `topologyManagerScope: pod` ou `container`) Vérifiez également le `topologyManagerScope` : ```yaml topologyManagerScope: container # ou pod ``` Et la politique du CPU Manager, car Topology Manager interagit avec lui : ```yaml cpuManagerPolicy: static ``` Si vous utilisez un fichier de configuration du kubelet, vérifiez que le kubelet l’utilise réellement. Examinez l’unité systemd du kubelet : ```bash systemctl cat kubelet ``` Trouvez le drapeau `--config`. Il doit pointer vers votre fichier. Sinon, le kubelet peut utiliser des drapeaux en ligne de commande, qui ont la priorité. Dans ce cas, vérifiez la ligne de commande : ```bash ps aux | grep kubelet ``` Recherchez des drapeaux comme `--topology-manager-policy` et `--cpu-manager-policy`. ### 3. Inspecter la topologie NUMA du nœud Vous devez connaître la disposition NUMA de vos nœuds. Utilisez `lscpu` sur un nœud : ```bash lscpu | grep -E 'NUMA|CPU\(s\)|On-line' ``` Exemple de sortie sur un serveur à deux sockets : ``` CPU(s): 32 On-line CPU(s) list: 0-31 NUMA node(s): 2 NUMA node0 CPU(s): 0-15 NUMA node1 CPU(s): 16-31 ``` Cela indique que le nœud possède deux nœuds NUMA, chacun avec 16 CPU. ### 4. Vérifier les plugins de périphériques et les ressources Si vous utilisez des périphériques comme des GPU ou des cartes réseau SR-IOV, listez les ressources étendues sur les nœuds : ```bash kubectl describe nodes | grep -A 5 'Capacity:' ``` Recherchez des entrées comme `nvidia.com/gpu: 2` ou `intel.com/sriov: 4`. Ces périphériques sont gérés par des plugins de périphériques, et Topology Manager tiendra compte de leur affinité NUMA. ### 5. Vérifier le comportement actuel de planification des pods Avant de modifier quoi que ce soit, observez comment les pods actuels sont placés. Pour un pod en cours d’exécution, vous pouvez voir ses CPU et nœuds NUMA attribués : ```bash kubectl get pod -o jsonpath='{.spec.containers[0].resources}' ``` Pour voir l’attribution réelle des CPU sur le nœud, vous pouvez utiliser `crictl` (si configuré) ou examiner le cgroup : ```bash sudo crictl inspect | grep -A 5 cpuset ``` Cependant, cela n’est souvent pas facilement accessible. Une méthode plus simple consiste à consulter les journaux du kubelet pour les décisions de Topology Manager : ```bash sudo journalctl -u kubelet | grep -i topology ``` Recherchez des lignes indiquant des indices d’alignement ou des échecs. ### Liste de contrôle pratique pour l’inventaire - [ ] Enregistrer les versions du serveur Kubernetes et du kubelet. - [ ] Documenter les valeurs actuelles de `topologyManagerPolicy` et `topologyManagerScope`. - [ ] Documenter la politique `cpuManagerPolicy` actuelle et les drapeaux associés. - [ ] Capturer la topologie NUMA pour chaque type de nœud. - [ ] Lister les ressources étendues et les plugins de périphériques. - [ ] Établir une base de référence du comportement de planification des pods (sélectionner quelques pods représentatifs). - [ ] Stocker cet inventaire dans un document versionné ou un dépôt Git. ## Chemin de configuration sûr Une fois que vous disposez d’un inventaire complet, planifiez soigneusement les modifications de configuration. Le principe clé est de ne faire qu’un seul changement à la fois et de vérifier son effet avant de continuer. ### 1. Décider de la configuration cible Réfléchissez à ce que vous voulez accomplir : - Migrer de `none` à `best-effort` : risque minimal, améliore l’alignement lorsque possible sans rejeter de pods. - Migrer de `none` ou `best-effort` à `restricted` : risque plus élevé ; les pods qui ne peuvent pas être alignés seront rejetés. - Changer `topologyManagerScope` de `container` à `pod` : peut augmenter la rigueur de l’alignement. - Mettre à niveau Kubernetes : peut apporter de nouvelles fonctionnalités de Topology Manager ou déprécier d’anciennes. Pour une première étape typique, l’activation de `best-effort` est une amélioration sûre. Exemple d’extrait de configuration du kubelet : ```yaml apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration topologyManagerPolicy: best-effort topologyManagerScope: container cpuManagerPolicy: static cpuManagerReconcilePeriod: 10s ``` ### 2. Choisir un nœud de test Ne déployez jamais les modifications sur tous les nœuds à la fois. Choisissez un nœud worker qui n’exécute pas de charges de travail critiques ou qui peut tolérer une interruption. Drainez le nœud avant d’apporter des modifications : ```bash kubectl drain --ignore-daemonsets --delete-emptydir-data ``` Cela évacue tous les pods du nœud. Le drapeau `--delete-emptydir-data` est nécessaire si des pods utilisent des volumes emptyDir ; sinon, le drainage restera bloqué. ### 3. Mettre à jour la configuration du kubelet Sur le nœud de test, modifiez le fichier de configuration du kubelet (par exemple, `/var/lib/kubelet/config.yaml`). Faites d’abord une sauvegarde : ```bash sudo cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak ``` Appliquez ensuite vos modifications. Par exemple, pour activer `best-effort` : ```bash sudo sed -i 's/topologyManagerPolicy: none/topologyManagerPolicy: best-effort/' /var/lib/kubelet/config.yaml ``` Si la ligne n’existe pas, ajoutez-la sous la section appropriée. Assurez-vous que l’indentation YAML est correcte. ### 4. Redémarrer le kubelet Redémarrez le kubelet pour appliquer la nouvelle configuration : ```bash sudo systemctl restart kubelet ``` Vérifiez qu’il fonctionne : ```bash sudo systemctl status kubelet ``` Recherchez des messages d’erreur dans le journal : ```bash sudo journalctl -u kubelet --since "5 minutes ago" | grep -i error ``` ### 5. Décordonner le nœud et tester la planification Autorisez à nouveau la planification des pods : ```bash kubectl uncordon ``` Déployez ensuite un pod de test simple qui demande plusieurs ressources, comme du CPU et de la mémoire, pour voir comment Topology Manager les aligne. Par exemple : ```yaml apiVersion: v1 kind: Pod metadata: name: topology-test spec: containers: - name: test image: nginx resources: requests: cpu: "2" memory: "1Gi" limits: cpu: "2" memory: "1Gi" ``` Appliquez et vérifiez sa planification : ```bash kubectl apply -f topology-test.yaml kubectl get pods -o wide ``` Si le pod est planifié, vérifiez les journaux du kubelet sur le nœud pour les décisions de Topology Manager : ```bash sudo journalctl -u kubelet | grep -i topology | tail -20 ``` Recherchez des messages indiquant des indices d’alignement ou une allocation réussie. ### 6. Surveiller et comparer Laissez le pod de test s’exécuter pendant un certain temps et surveillez tout comportement inattendu. Supprimez-le ensuite : ```bash kubectl delete pod topology-test ``` Comparez le comportement du nœud avant et après le changement. Si tout va bien, passez au nœud suivant, un à la fois. ## Vérification et diagnostics Après avoir appliqué les modifications, vous devez vérifier que Topology Manager applique la politique prévue et que les pods sont planifiés comme attendu. Cette section fournit des commandes et des techniques de diagnostic. ### 1. Vérifier la configuration active Sur le nœud, vérifiez la configuration effective du kubelet : ```bash sudo kubectl get --raw /api/v1/nodes//proxy/configz | jq '.kubeletconfig.topologyManagerPolicy' ``` Cela interroge le point de terminaison configz du kubelet (nécessite que le serveur API dispose d’un accès proxy). La sortie doit afficher votre politique configurée, par exemple, `"best-effort"`. Si configz n’est pas disponible, vérifiez le processus kubelet en cours d’exécution : ```bash ps aux | grep kubelet | grep -o 'topology-manager-policy=[^ ]*' ``` Si vous utilisez un fichier de configuration, vous pouvez également vérifier le contenu du fichier : ```bash sudo grep topologyManagerPolicy /var/lib/kubelet/config.yaml ``` ### 2. Tester avec un pod nécessitant un alignement Déployez un pod avec une qualité de service Garantie (requêtes égales aux limites) et plusieurs ressources : ```yaml apiVersion: v1 kind: Pod metadata: name: strict-alignment-test spec: containers: - name: test image: nginx resources: requests: cpu: "4" memory: "4Gi" ephemeral-storage: "1Gi" limits: cpu: "4" memory: "4Gi" ephemeral-storage: "1Gi" ``` Ce pod demande une quantité spécifique de CPU et de mémoire qui doit être alignée. Appliquez et vérifiez s’il est planifié : ```bash kubectl apply -f strict-alignment-test.yaml kubectl get pods -o wide ``` Si la politique est `restricted` et que le nœud ne peut pas satisfaire l’alignement, le pod restera à l’état `Pending`. Vérifiez les événements du pod pour un message détaillé : ```bash kubectl describe pod strict-alignment-test ``` Recherchez un événement comme : ``` Warning FailedScheduling 10s default-scheduler 0/3 nodes are available: 3 node(s) had untolerated taint {node.kubernetes.io/not-ready: }, 3 node(s) didn't match Pod's node affinity/selector. ``` Ou, si le planificateur l’a autorisé mais que le kubelet l’a rejeté : ``` Warning Failed 12s kubelet admission failed: topology manager policy "restricted" cannot allocate resources ``` ### 3. Inspecter les journaux du kubelet pour les décisions de topologie Sur le nœud, utilisez `journalctl` pour voir les journaux détaillés : ```bash sudo journalctl -u kubelet --since "10 minutes ago" | grep -i topology ``` Pour une allocation réussie, vous pourriez voir : ``` I0523 10:15:32.123456 12345 topology_manager.go:215] [topologymanager] Topology Manager policy best-effort, hints: {01 true} ``` Pour un échec sous `restricted` : ``` E0523 10:20:11.654321 12345 topology_manager.go:187] [topologymanager] Topology Manager policy restricted, unable to find aligned resources for container test ``` ### 4. Utiliser Node Resource Topology (si disponible) Kubernetes 1.27+ peut avoir l’API Node Resource Topology activée. Vous pouvez l’interroger pour voir la disponibilité des ressources par nœud NUMA : ```bash kubectl get noderesourcetopologies ``` Exemple de sortie : ``` NAME AGE node-1 5d node-2 5d ``` Décrivez-en un : ```bash kubectl describe noderesourcetopologies node-1 ``` Recherchez les sections `topologyPolicies` et `zones` pour comprendre la disposition NUMA et les ressources. Si cette API n’est pas activée, vous pouvez toujours inspecter l’allocation des ressources du nœud via le point de terminaison `/metrics` du kubelet pour `container_resources_cpu_usage`, mais cela est moins spécifique à la topologie. ### 5. Liste de contrôle de diagnostic - Confirmer que le kubelet utilise la configuration prévue. - Déployer un pod de test nécessitant un alignement et observer sa planification. - Vérifier les événements du pod et les journaux du kubelet pour les messages liés à la topologie. - Si le pod est rejeté, comprendre pourquoi (distribution des ressources, politique trop stricte). - Si le pod est accepté, vérifier l’attribution réelle CPU/NUMA (si possible via le cpuset du cgroup). - Comparer le comportement entre les nœuds si vous avez plusieurs types de nœuds. ## Modes de défaillance et récupération Quelle que soit votre prudence, des problèmes peuvent survenir. Cette section couvre les scénarios de défaillance courants et comment s’en remettre. ### 1. Le kubelet ne démarre pas après un changement de configuration **Symptôme** : Après avoir modifié le fichier de configuration et redémarré le kubelet, le nœud devient `NotReady`. **Diagnostic** : Vérifiez l’état et les journaux du kubelet : ```bash sudo systemctl status kubelet sudo journalctl -u kubelet --since "5 minutes ago" ``` Les erreurs possibles incluent un YAML mal formé ou une valeur de politique invalide. **Récupération** : Restaurez la configuration de sauvegarde : ```bash sudo cp /var/lib/kubelet/config.yaml.bak /var/lib/kubelet/config.yaml sudo systemctl restart kubelet ``` Attendez que le nœud redevienne Ready : ```bash kubectl get nodes ``` ### 2. Les pods ne sont pas planifiés ou sont évincés **Symptôme** : Après avoir activé `restricted` ou changé la portée, certains pods passent à `Pending` ou sont évincés. **Diagnostic** : Vérifiez les événements du pod : ```bash kubectl describe pod ``` Recherchez des messages concernant une inadéquation du Topology Manager ou des ressources insuffisantes. **Récupération** : Si les pods sont critiques, revenez à la politique `best-effort` ou `none` sur le(s) nœud(s) affecté(s), en suivant la même procédure de drainage et de cordon. Ajustez également les requêtes de ressources du pod pour qu’elles soient alignables. ### 3. Dégradation des performances due à un alignement sous-optimal **Symptôme** : Les applications s’exécutent plus lentement après le changement, peut-être parce qu’elles sont désormais épinglées à un seul nœud NUMA et ne peuvent pas utiliser la mémoire distante. **Diagnostic** : Comparez les métriques des applications avant et après. Vérifiez si le pod est restreint à un seul nœud NUMA (en utilisant le cpuset du cgroup). **Récupération** : Envisagez d’utiliser `best-effort` au lieu de `restricted` pour plus de flexibilité. Ou ajustez les ressources du pod pour qu’elles tiennent dans un nœud NUMA si vous souhaitez un alignement strict. ### 4. Problèmes de compatibilité des plugins de périphériques **Symptôme** : Les pods demandant des GPU ou d’autres périphériques ne sont pas planifiés après le changement de Topology Manager. **Diagnostic** : Vérifiez les journaux du plugin de périphériques et du kubelet pour les erreurs. Le plugin peut ne pas prendre en charge correctement les indices de topologie. **Récupération** : Mettez à jour le plugin de périphériques vers une version qui prend en charge Topology Manager. Ou désactivez Topology Manager pour les pods utilisant ces périphériques en utilisant un espace de noms ou une annotation différente (si pris en charge). ### 5. Comportement incohérent entre les nœuds **Symptôme** : Certains nœuds acceptent des pods tandis que d’autres les rejettent, même s’ils ont des spécifications similaires. **Diagnostic** : Vérifiez les différences de topologie NUMA. Certains nœuds peuvent avoir un nombre différent de nœuds NUMA ou une distribution des ressources variée. **Récupération** : Standardisez le matériel des nœuds ou ajustez la politique par type de nœud. Vous pouvez utiliser des overrides de configuration du kubelet par groupe de nœuds (par exemple, via des étiquettes de nœud et des fichiers de configuration séparés). ### Stratégies générales de récupération - Toujours garder une sauvegarde de la configuration du kubelet avant les modifications. - Apporter les modifications un nœud à la fois pour limiter l’impact. - Disposer d’une méthode pour drainer et cordonner rapidement les nœuds. - Documenter la procédure exacte de retour en arrière. - Tester la restauration sur un nœud hors production d’abord, si possible. ## Pièges courants et comment les éviter Cette section met en évidence les erreurs fréquentes et fournit des conseils pour les prévenir ou s’en remettre. ### 1. Ne pas vérifier la topologie NUMA matérielle avant d’activer des politiques strictes **Piège** : Activer `restricted` ou `single-numa-node` sur des nœuds avec plusieurs nœuds NUMA sans comprendre la distribution des ressources peut entraîner de nombreux rejets de pods. **Comment éviter** : Utilisez `lscpu` pour cartographier les nœuds NUMA et les CPU. Testez d’abord avec `best-effort` et surveillez le succès de l’alignement. **Récupération** : Revenez à `best-effort` si trop de pods échouent. ### 2. Ignorer la configuration du kubelet via les drapeaux de ligne de commande **Piège** : Modifier le fichier de configuration sans se rendre compte que le kubelet utilise des drapeaux en ligne de commande qui remplacent le fichier. **Comment éviter** : Vérifiez `ps aux | grep kubelet` et l’unité systemd pour `--config` versus les drapeaux individuels. Utilisez une seule méthode de manière cohérente. **Récupération** : Mettez à jour les drapeaux ou supprimez-les et fiez-vous au fichier de configuration. ### 3. Appliquer les modifications à tous les nœuds à la fois **Piège** : Déployer un changement de Topology Manager dans tout le cluster sans test canari peut provoquer des échecs de planification généralisés. **Comment éviter** : Utilisez un déploiement progressif : un nœud à la fois, surveillez, puis continuez. Envisagez d’utiliser des pools de nœuds ou des déploiements de machines pour gérer différentes configurations. **Récupération** : Si vous avez déjà déployé sur de nombreux nœuds, drainez et revenez rapidement sur chaque nœud, ou utilisez un outil de gestion de configuration pour pousser l’ancienne configuration. ### 4. Négliger l’impact sur les pods Garantis **Piège** : Les pods avec une qualité de service Garantie (requêtes égales aux limites) sont toujours pris en compte pour un alignement strict. Si vous activez `restricted`, tous ces pods doivent être alignables. **Comment éviter** : Avant l’activation, passez en revue les pods Garantis existants et leurs requêtes de ressources. Déterminez s’ils peuvent tenir dans les contraintes NUMA. **Récupération** : Ajustez les ressources du pod ou utilisez `best-effort` si l’alignement n’est pas critique. ### 5. Ne pas tenir compte de l’interaction avec la politique du CPU Manager **Piège** : Topology Manager travaille en étroite collaboration avec CPU Manager. Si la politique du CPU Manager est `none`, Topology Manager a un effet limité pour le CPU. **Comment éviter** : Décidez de la politique du CPU Manager (`static` est recommandé pour un alignement strict) et configurez-la avec Topology Manager. **Récupération** : Assurez-vous que les deux politiques sont cohérentes. ### 6. Oublier de vérifier les ressources étendues et les plugins de périphériques **Piège** : Les périphériques comme les GPU peuvent avoir leurs propres indices de topologie. Si le plugin est obsolète ou mal configuré, Topology Manager peut ne pas recevoir d’indices corrects. **Comment éviter** : Mettez à jour les plugins de périphériques vers des versions qui prennent en charge Topology Manager. Testez avec des périphériques factices si possible. **Récupération** : Désactivez Topology Manager pour les pods utilisant des périphériques ou mettez à jour le plugin. ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle pour assurer une mise à niveau ou une migration fluide. Chaque élément inclut un responsable (une seule personne responsable) et une fréquence de révision. | # | Tâche | Responsable | Fréquence / Date de révision | |---|-------|-------------|-----------------------------| | 1 | Inventorier les versions actuelles de Kubernetes/kubelet, la configuration de topologie et la disposition NUMA | Priya Shah, ingénieure plateforme | Avant chaque changement ; audit trimestriel | | 2 | Décider de la politique et de la portée cibles de Topology Manager | Marcus Chen, responsable ingénierie | Par cycle de mise à niveau | | 3 | Sélectionner un nœud de test et le drainer | Priya Shah | Par déploiement | | 4 | Sauvegarder la configuration du kubelet et appliquer les modifications sur le nœud de test | Priya Shah | Par nœud | | 5 | Redémarrer le kubelet et vérifier l’état | Priya Shah | Immédiatement après le changement | | 6 | Décordonner le nœud et déployer un pod de test pour valider la planification | Marcus Chen | Après que le nœud est prêt | | 7 | Surveiller les journaux du kubelet et les événements du pod pour les décisions de topologie | Priya Shah | En continu pendant le pilote | | 8 | En cas de succès, passer au nœud suivant un par un | Marcus Chen | Quotidiennement pendant le déploiement | | 9 | En cas d’échec, exécuter la procédure de retour en arrière documentée | Priya Shah | Au besoin | | 10 | Documenter les résultats et mettre à jour les procédures opérationnelles | Priya Shah | Après chaque changement ; révision mensuelle | ## Conclusion La mise à niveau ou la migration de Kubernetes Topology Manager est une opération délicate qui nécessite une planification minutieuse, une exécution incrémentale et une vérification approfondie. En suivant les procédures de ce guide - de l’inventaire initial à la configuration sûre, en passant par la validation, les diagnostics et la récupération - vous pouvez minimiser les risques et obtenir un meilleur alignement des ressources dans votre cluster. N’oubliez pas que chaque cluster est différent, et ce qui fonctionne dans un environnement peut ne pas fonctionner dans un autre. Testez toujours d’abord dans un environnement de préproduction ou canari, et ayez un plan de retour en arrière solide. Gardez vos configurations de kubelet sous contrôle de version et documentez chaque changement. Comme prochaine étape, choisissez une vérification à faible risque (par exemple, activer `best-effort` sur un seul nœud) et suivez la liste de contrôle. Enregistrez l’état actuel, exécutez le changement, comparez le comportement attendu et réel, et examinez les dépendances telles que CPU Manager, les plugins de périphériques et les politiques de planification. Avec une approche méthodique, vous pouvez tirer parti de Topology Manager en toute sécurité pour améliorer les performances des charges de travail et l’utilisation des ressources.