## Introduction Les taints et les tolérances sont un mécanisme fondamental de planification de Kubernetes qui permet de contrôler quels pods peuvent être placés sur quels nœuds. Les taints sont appliquées aux nœuds pour repousser les pods qui ne les tolèrent pas, tandis que les tolérances sont appliquées aux pods pour leur permettre d'être planifiés sur des nœuds contaminés. En production, une taint ou une tolérance mal configurée peut entraîner des pods bloqués en état Pending, des charges de travail non planifiables, voire la planification accidentelle de pods critiques sur des nœuds inadaptés. Cet article fournit une liste de contrôle opérationnelle axée sur la production pour les taints et tolérances de Kubernetes. Il couvre l'inventaire des versions et de l'environnement, les chemins de configuration sécuritaires, la vérification et le diagnostic, les modes de défaillance et la récupération, ainsi qu'une liste de contrôle opérationnelle de bout en bout. Chaque section comprend des commandes `kubectl` concrètes, les sorties attendues et des exemples pratiques. 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. Ce guide est destiné aux développeurs, consultants DevOps et équipes techniques de startups qui doivent gérer les taints et tolérances dans des clusters de production. Il suppose une familiarité de base avec les concepts de Kubernetes tels que les pods, les nœuds et les Deployments. ## Inventaire des versions et de l'environnement Avant d'apporter des modifications, vous devez connaître votre version de Kubernetes, la topologie du cluster et l'état exact de vos taints et tolérances. Les taints et tolérances ont évolué au fil des versions de Kubernetes ; par exemple, les taints `node.kubernetes.io/not-ready` et `node.kubernetes.io/unreachable` se comportent différemment selon la version et la porte de fonctionnalité `TaintBasedEvictions`. ### 1. Vérifier la version de Kubernetes Exécutez la commande suivante pour vérifier la version du serveur : ```bash kubectl version --short ``` Sortie attendue (exemple) : ``` Client Version: v1.25.3 Server Version: v1.25.3 ``` Remarque : Dans les versions plus récentes, le drapeau `--short` est obsolète ; utilisez `kubectl version` sans drapeaux et lisez la sortie. Si vos versions client et serveur diffèrent considérablement, sachez que les champs d'API liés aux taints peuvent se comporter différemment. Pour la production, documentez la version exacte dans votre cahier de procédures (runbook). ### 2. Lister tous les nœuds et leurs taints Pour voir tous les nœuds et leurs taints : ```bash kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints ``` Sortie attendue (exemple) : ``` NAME TAINTS node-1 node-2 [{"effect":"NoSchedule","key":"dedicated","value":"database"}] node-3 [{"effect":"NoExecute","key":"gpu","value":"true"}] ``` Si un nœud affiche `` pour les taints, il n'a pas de taints et tout pod sans tolérance correspondante peut y être planifié. Recherchez les taints avec `NoSchedule` (les pods sans tolérance ne seront pas planifiés), `PreferNoSchedule` (préférence douce) et `NoExecute` (évince les pods existants sans tolérance et empêche la planification). ### 3. Décrire un nœud spécifique Pour obtenir des informations détaillées sur les taints et les événements : ```bash kubectl describe node node-2 ``` Recherchez la ligne `Taints:` dans la sortie. Exemple : ``` Taints: dedicated=database:NoSchedule ``` Cela vous indique la clé de taint (`dedicated`), la valeur (`database`) et l'effet (`NoSchedule`). ### 4. Vérifier les pods existants et leurs tolérances Pour voir quels pods ont actuellement des tolérances : ```bash kubectl get pods -A -o json | jq '.items[] | {name: .metadata.name, namespace: .metadata.namespace, tolerations: .spec.tolerations}' ``` Sortie attendue (exemple) : ```json { "name": "my-db-pod", "namespace": "default", "tolerations": [ { "key": "dedicated", "operator": "Equal", "value": "database", "effect": "NoSchedule" } ] } ``` Si un pod ne liste aucune tolérance, il ne sera pas planifié sur des nœuds avec des taints, sauf si la taint a l'effet `PreferNoSchedule` (auquel cas le planificateur peut quand même le placer si aucun autre nœud n'est disponible). ### 5. Liste de contrôle de l'inventaire de l'environnement Pour la production, enregistrez les éléments suivants dans votre inventaire : - Version de Kubernetes (serveur et client) - Noms des nœuds et leurs taints - Espaces de noms et charges de travail qui dépendent des taints/tolérances - Pods critiques et leurs tolérances - Paramètres de l'autoscaler de cluster qui interagissent avec les taints Documentez cela dans un cahier de procédures avant d'apporter des modifications. ## Chemin de configuration sécuritaire Lors de la modification des taints ou des tolérances, suivez toujours un chemin de configuration sécuritaire : observez, planifiez, modifiez un élément à la fois, vérifiez et ayez un plan de retour en arrière. ### 1. Ajouter une taint à un nœud Pour ajouter une taint à un nœud : ```bash kubectl taint nodes node-1 dedicated=frontend:NoSchedule ``` Sortie attendue : ``` node/node-1 tainted ``` Cette taint empêche tout pod qui n'a pas de tolérance correspondante d'être planifié sur `node-1`. Après l'ajout, vérifiez avec : ```bash kubectl describe node node-1 | grep Taints ``` Sortie attendue : ``` Taints: dedicated=frontend:NoSchedule ``` ### 2. Ajouter une tolérance à la spécification d'un pod Les tolérances sont ajoutées à la spécification du pod. Pour un Deployment, ajoutez-les sous `spec.template.spec.tolerations`. Extrait YAML d'exemple : ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: frontend spec: replicas: 2 selector: matchLabels: app: frontend template: metadata: labels: app: frontend spec: tolerations: - key: "dedicated" operator: "Equal" value: "frontend" effect: "NoSchedule" containers: - name: nginx image: nginx:1.21 ``` Appliquez-le avec : ```bash kubectl apply -f frontend-deployment.yaml ``` Vérifiez ensuite l'état du déploiement : ```bash kubectl rollout status deployment/frontend ``` Sortie attendue : ``` deployment "frontend" successfully rolled out ``` ### 3. Supprimer une taint d'un nœud Pour supprimer une taint, utilisez la même clé et le même effet avec un signe moins à la fin de l'effet : ```bash kubectl taint nodes node-1 dedicated=frontend:NoSchedule- ``` Sortie attendue : ``` node/node-1 untainted ``` Vérifiez avec `kubectl describe node node-1` et assurez-vous que la taint a disparu. ### 4. Mettre à jour les tolérances sur un Deployment existant Si vous devez ajouter des tolérances à un déploiement existant sans le recréer, utilisez `kubectl patch` : ```bash kubectl patch deployment frontend --type='json' -p='[{"op": "add", "path": "/spec/template/spec/tolerations", "value": [{"key": "dedicated", "operator": "Equal", "value": "frontend", "effect": "NoSchedule"}]}]' ``` Surveillez ensuite le déploiement : ```bash kubectl rollout status deployment/frontend ``` ### 5. Pratiques de modification sécuritaires - Appliquez toujours les modifications à un environnement hors production d'abord si possible. - Utilisez `--dry-run=client` pour prévisualiser les modifications sans les appliquer. Pour les taints, vous pouvez simuler en utilisant `kubectl taint nodes node-1 dedicated=frontend:NoSchedule --dry-run=client` (bien que les taints soient des mutations côté serveur et que le dry-run peut ne pas s'appliquer complètement ; vérifiez avec `kubectl auth can-i` et testez dans un cluster de staging). - Documentez la commande exacte et sa sortie attendue avant de l'exécuter. - Ayez une commande de retour en arrière prête (par exemple, la commande pour supprimer la taint). - Limitez le rayon d'impact : modifiez un nœud ou un pod à la fois, puis observez. ## Vérification et diagnostic Après avoir apporté des modifications, vous devez vérifier que la planification se comporte comme prévu et diagnostiquer tout problème. ### 1. Vérifier l'état de planification des pods Listez les pods avec leurs affectations de nœuds : ```bash kubectl get pods -o wide ``` Sortie attendue (exemple) : ``` NAME READY STATUS RESTARTS AGE IP NODE frontend-6f8c9d7b-abcde 1/1 Running 0 10m 10.244.1.5 node-1 frontend-6f8c9d7b-fghij 1/1 Running 0 10m 10.244.2.3 node-2 ``` Si les pods sont bloqués en état `Pending`, ils peuvent être non planifiables en raison de taints. ### 2. Décrire un pod en attente Décrivez le pod pour voir les événements de planification : ```bash kubectl describe pod frontend-6f8c9d7b-abcde ``` Recherchez des événements comme : ``` Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 2m default-scheduler 0/3 nodes are available: 1 node(s) had taint {dedicated: frontend}, that the pod didn't tolerate, 2 node(s) had taint {gpu: true}, that the pod didn't tolerate. ``` Cet événement indique que le pod n'a pas les tolérances requises pour les taints sur les nœuds disponibles. ### 3. Vérifier les taints des nœuds après modification Utilisez à nouveau `kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints` pour confirmer que la taint est présente ou supprimée. ### 4. Vérifier les journaux pour les problèmes de démarrage Si un pod est en cours d'exécution mais se comporte mal, vérifiez ses journaux : ```bash kubectl logs --previous ``` Par exemple, si un pod a planté en raison de ressources manquantes sur un nœud contaminé, les journaux peuvent montrer des erreurs. ### 5. Utiliser les événements Kubernetes Pour voir les événements à l'échelle du cluster liés à la planification : ```bash kubectl get events --field-selector reason=FailedScheduling ``` Cela filtre les événements pour les échecs de planification. ### 6. Simuler la planification avec `kubectl debug` ou un essai à blanc Vous pouvez utiliser la commande `kubectl debug` pour créer un pod temporaire avec des tolérances afin de tester la planification sur un nœud spécifique. Par exemple : ```bash kubectl debug node/node-1 -it --image=busybox -- sh ``` Cela crée un pod de débogage sur node-1, ce qui peut nécessiter des tolérances si node-1 est contaminé. Alternativement, utilisez un manifeste avec `--dry-run` pour voir si le pod serait accepté : ```bash kubectl apply -f test-pod.yaml --dry-run=client ``` Cela ne valide que le YAML, pas la planification. Pour une simulation réelle de planification, utilisez un outil comme `kube-scheduler-simulator` ou testez dans un cluster de staging. ## Modes de défaillance et récupération Des taints et tolérances mal configurées peuvent causer plusieurs modes de défaillance. Voici des scénarios courants et les étapes de récupération. ### Mode de défaillance 1 : Pod bloqué en état Pending en raison d'une tolérance manquante **Symptôme :** `kubectl get pods` montre un pod avec STATUS `Pending` pendant une longue période. La description du pod montre des événements `FailedScheduling` avec des messages sur les taints. **Récupération :** 1. Identifiez les taints sur les nœuds : ```bash kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints ``` 2. Déterminez quelle taint bloque. Ajoutez la tolérance appropriée à la spécification du pod. Pour une correction rapide, patchez le déploiement : ```bash kubectl patch deployment --type='json' -p='[{"op": "add", "path": "/spec/template/spec/tolerations", "value": [{"key": "", "operator": "Equal", "value": "", "effect": ""}]}]' ``` 3. Surveillez la planification des nouveaux pods : ```bash kubectl get pods -w ``` ### Mode de défaillance 2 : Pod évincé par une taint NoExecute **Symptôme :** Un pod en cours d'exécution se termine soudainement et est recréé à plusieurs reprises, ou disparaît du nœud. La description du pod peut montrer un événement d'éviction. **Récupération :** 1. Vérifiez les taints du nœud : `kubectl describe node `. 2. Si une taint `NoExecute` a été récemment ajoutée, ajoutez une tolérance avec `tolerationSeconds` ou `operator: Exists` au pod, ou supprimez la taint du nœud si elle n'était pas intentionnelle. 3. Supprimez la taint : ```bash kubectl taint nodes =:NoExecute- ``` 4. Vérifiez que le pod se replanifie : ```bash kubectl get pods -o wide ``` ### Mode de défaillance 3 : Tous les nœuds sont contaminés et aucun pod ne peut être planifié **Symptôme :** Chaque nouveau pod reste Pending, et `kubectl get nodes` montre que tous les nœuds ont des taints sans tolérances correspondantes. **Récupération :** 1. Listez les taints : ```bash kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints ``` 2. Décidez s'il faut supprimer les taints de certains nœuds ou ajouter des tolérances aux charges de travail critiques. 3. Pour les pods système critiques (par exemple, kube-system), assurez-vous qu'ils ont des tolérances appropriées ; de nombreux pods système ont des tolérances intégrées pour les taints courantes comme `node.kubernetes.io/not-ready`. 4. Supprimez les taints inutiles ou ajoutez une tolérance large : ```yaml tolerations: - operator: "Exists" ``` À utiliser avec prudence, car cela permet au pod de se planifier sur n'importe quel nœud contaminé. ### Mode de défaillance 4 : Taint supprimée mais les pods restent non planifiables **Symptôme :** Après la suppression d'une taint, les pods ne peuvent toujours pas se planifier sur un nœud. **Causes possibles :** - La commande de suppression de taint avait une faute de frappe ou un mauvais effet. - Il y a d'autres taints sur le nœud. - Le nœud est cordonné (`kubectl cordon`). - Des contraintes de ressources (CPU/mémoire) empêchent la planification. **Récupération :** 1. Vérifiez les taints du nœud et l'état de cordon : ```bash kubectl describe node | grep -E 'Taints|Unschedulable' ``` 2. Si `Unschedulable: true`, décordonnez le nœud : ```bash kubectl uncordon ``` 3. Vérifiez les autres taints et supprimez-les si approprié. 4. Vérifiez les demandes et limites de ressources des pods et la capacité allouable du nœud. ### Stratégies de retour en arrière Ayez toujours un plan de retour en arrière : - Pour les taints, conservez la commande exacte pour supprimer la taint (avec le signe moins final). - Pour les tolérances des pods, conservez le YAML précédent ou la commande patch pour revenir en arrière. - Utilisez le contrôle de version pour tous les manifestes. ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle pour les opérations courantes sur les taints et tolérances en production. ### Avant d'apporter des modifications - [ ] Enregistrez la version actuelle de Kubernetes : `kubectl version --short` - [ ] Enregistrez les taints actuelles des nœuds : `kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints` - [ ] Identifiez les charges de travail affectées et leurs tolérances actuelles - [ ] Prenez une sauvegarde des manifestes pertinents ou utilisez Git pour le contrôle de version - [ ] Préparez les commandes de retour en arrière - [ ] Évaluez le rayon d'impact : combien de pods/nœuds seront affectés ? ### Pendant la modification - [ ] Appliquez la modification à un nœud ou une charge de travail à la fois - [ ] Utilisez des commandes exactes et enregistrez la sortie - [ ] Surveillez immédiatement les pods et les nœuds : `kubectl get pods -w` et `kubectl get nodes -w` - [ ] Vérifiez les évictions ou échecs de planification inattendus ### Après la modification - [ ] Vérifiez les taints du nœud : `kubectl describe node | grep Taints` - [ ] Vérifiez la planification des pods : `kubectl get pods -o wide` - [ ] Vérifiez l'état du déploiement : `kubectl rollout status deployment/` - [ ] Passez en revue les événements : `kubectl get events --sort-by=.metadata.creationTimestamp` - [ ] Mettez à jour le cahier de procédures avec la modification et le résultat - [ ] Assurez-vous que les alertes de surveillance ne se déclenchent pas en raison de la modification ### Exemple d'entrée de cahier de procédures Considérez un scénario où vous devez dédier un nœud aux pods de base de données. Voici un exemple d'entrée de cahier de procédures : **Objectif :** S'assurer que seuls les pods de base de données s'exécutent sur node-2. **Prérequis :** Kubernetes v1.25, accès au cluster, YAML de déploiement de la base de données. **Étapes :** 1. Vérifiez les taints actuelles sur node-2 : ```bash kubectl describe node node-2 | grep Taints ``` Si aucune, continuez. 2. Ajoutez une taint à node-2 : ```bash kubectl taint nodes node-2 dedicated=database:NoSchedule ``` Sortie : `node/node-2 tainted` 3. Mettez à jour le déploiement de la base de données pour inclure la tolérance : ```bash kubectl patch deployment database --type='json' -p='[{"op": "add", "path": "/spec/template/spec/tolerations", "value": [{"key": "dedicated", "operator": "Equal", "value": "database", "effect": "NoSchedule"}]}]' ``` 4. Attendez le déploiement : ```bash kubectl rollout status deployment/database ``` Sortie : `deployment "database" successfully rolled out` 5. Vérifiez que les pods de base de données sont sur node-2 : ```bash kubectl get pods -o wide -l app=database ``` Assurez-vous que tous les pods affichent NODE=node-2. 6. Vérifiez qu'aucun autre pod n'est sur node-2 (si souhaité) : ```bash kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=node-2 ``` Si d'autres pods sont en cours d'exécution, ils peuvent devoir être évincés ou recevoir des tolérances appropriées (attention aux pods système). **Retour en arrière :** - Supprimez la taint : `kubectl taint nodes node-2 dedicated=database:NoSchedule-` - Supprimez la tolérance du déploiement si nécessaire. **Vérification :** - Confirmez que les pods de base de données sont en cours d'exécution et qu'il n'y a pas d'erreurs de planification. - Vérifiez à nouveau les taints du nœud. ## Conclusion Les taints et tolérances sont des outils puissants pour contrôler le placement des pods dans Kubernetes, mais ils nécessitent une gestion prudente en production. En suivant la liste de contrôle opérationnelle de cet article, vous pouvez éviter les pièges courants tels que les pods non planifiables, les évictions inattendues et les mauvaises configurations de nœuds. N'oubliez pas de toujours observer avant de modifier, de limiter le rayon d'impact, d'utiliser des espaces réservés au lieu de secrets, de vérifier les résultats avec des commandes concrètes et de documenter les procédures de récupération avant qu'un incident ne force la décision. Révisez régulièrement vos taints et tolérances à mesure que votre cluster évolue et tenez vos cahiers de procédures à jour. Comme prochaine étape, choisissez une modification à faible risque dans un environnement de staging, appliquez la liste de contrôle et validez votre compréhension. Ensuite, apportez la même rigueur à la production.