PerfectScalePerfectScale

PerfectScale

Node Affinity : le guide complet avec exemples, cas d'usage et conseils de pro

Cette page est également disponible en English, Deutsch, Español, Italiano, 日本語 et Português.

Aug 30, 202612 min read
Josh Palmer

About Josh Palmer

Head of Content

I'm Josh Palmer, Head of Content at DoiT, where I split my time across multiple business units including DoiT Cloud Intelligence, PerfectScale (Kubernetes cost optimization), and SELECT (Snowflake, Databricks, and BigQuery cost optimization). Before DoiT, I spent four and a half years at OnBoard building content for a board intelligence platform used by 6,000+ organizations, and before that, two years as Content Marketing Manager at Zylo, a SaaS management platform.

My personal page

En bref : L'affinité de nœuds (node affinity) permet de restreindre les nœuds sur lesquels un pod peut s'exécuter en fonction des labels de nœuds, via des règles strictes (requiredDuringSchedulingIgnoredDuringExecution) ou souples (preferredDuringSchedulingIgnoredDuringExecution). Plus expressive que nodeSelector, elle sert couramment à cibler des nœuds GPU/SSD, à maintenir des workloads dans une zone donnée ou à séparer la production du développement. Standardisez les labels de nœuds, privilégiez les règles souples sauf si le placement est impératif, et alignez l'affinité avec l'autoscaling et le dimensionnement des workloads pour éviter que les pods ne restent bloqués en Pending.

Dans cet article :

Qu'est-ce que l'affinité de nœuds dans Kubernetes ?

L'affinité de nœuds (node affinity) dans Kubernetes est un ensemble de règles permettant de restreindre les nœuds sur lesquels un pod peut être planifié, en fonction des labels attribués aux nœuds. Elle offre une logique de planification plus expressive et plus complexe que nodeSelector, avec des règles souples et strictes pour placer les pods sur du matériel spécifique et labellisé, comme des SSD ou des GPU.

Cette fonctionnalité est particulièrement utile dans les clusters Kubernetes multi-tenant, hybrides ou hétérogènes, où les workloads peuvent avoir des exigences variées en matière de matériel ou de localisation. L'affinité de nœuds vous permet d'optimiser l'utilisation des ressources, d'isoler les workloads sensibles et d'améliorer les performances applicatives en associant chaque workload aux nœuds présentant les caractéristiques les plus adaptées.

Principaux types d'affinité de nœuds :

  • Règles strictes (requiredDuringSchedulingIgnoredDuringExecution) : le scheduler doit trouver un nœud correspondant pour placer le pod ; sinon, celui-ci reste en état Pending.
  • Règles souples (preferredDuringSchedulingIgnoredDuringExecution) : le scheduler tente de trouver un nœud correspondant, mais si aucun n'est disponible, il planifie tout de même le pod ailleurs.

Exemple d'utilisation (YAML) :

spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd

Cet article fait partie d'une série consacrée à la planification Kubernetes.

Fonctionnement de l'affinité de nœuds dans Kubernetes

Voici les principaux éléments techniques qui sous-tendent l'affinité de nœuds.

Les labels de nœuds

Les labels de nœuds sont des paires clé-valeur attachées aux nœuds Kubernetes pour décrire leurs attributs. Les labels sont arbitraires et peuvent représenter des caractéristiques telles que le type d'instance, la région, la zone de disponibilité ou des métadonnées personnalisées utiles à la planification des workloads. Par exemple, vous pouvez labelliser des nœuds avec disktype=ssd ou gpu=true pour identifier ceux qui disposent d'un stockage SSD ou d'une accélération GPU.

Les labels sont définis par les administrateurs du cluster ou par des scripts d'automatisation, soit lors de l'ajout des nœuds au cluster, soit dynamiquement au fil des évolutions de l'infrastructure. Une labellisation cohérente et pertinente est essentielle à une affinité de nœuds efficace, car les règles d'affinité s'appuient sur ces labels pour sélectionner les nœuds appropriés au placement des pods. Une labellisation rigoureuse garantit que le scheduler peut interpréter et appliquer correctement vos politiques de placement.

Les opérateurs d'affinité de nœuds

Les règles d'affinité de nœuds utilisent des opérateurs pour définir la manière dont les pods doivent correspondre aux labels des nœuds. Les opérateurs les plus courants sont In, NotIn, Exists et DoesNotExist. Les opérateurs In et NotIn permettent de spécifier des valeurs acceptables ou non pour un label donné, tandis qu'Exists et DoesNotExist vérifient la présence ou l'absence d'une clé de label, quelle que soit sa valeur.

Ces opérateurs offrent une grande flexibilité pour exprimer des exigences de planification complexes. Par exemple, vous pouvez imposer que des pods s'exécutent uniquement sur des nœuds où environment=production, ou éviter les nœuds portant dedicated=backup. En combinant différents opérateurs et sélecteurs de labels, vous pouvez affiner le placement des pods pour répondre aux exigences des workloads et aux politiques de votre organisation.

Le comportement du scheduler

Le scheduler Kubernetes évalue les règles d'affinité de nœuds au moment de décider où placer un pod. Il compare les labels des nœuds disponibles aux critères d'affinité définis dans la spécification du pod. Si un nœud satisfait les règles d'affinité requises, il devient éligible pour accueillir le pod ; sinon, le pod reste non planifié jusqu'à ce qu'un nœud adapté soit disponible.

Il existe deux types d'affinité de nœuds : requise (stricte) et préférée (souple). Les règles requises doivent être satisfaites pour que le pod soit planifié, tandis que les règles préférées influencent le choix du scheduler sans empêcher la planification si aucun nœud préféré n'est disponible. Cette distinction permet des stratégies de placement à la fois strictes et flexibles, en équilibrant besoins opérationnels et disponibilité des ressources.

Syntaxe YAML de l'affinité de nœuds : règles strictes et souples

1. RequiredDuringSchedulingIgnoredDuringExecution

requiredDuringSchedulingIgnoredDuringExecution définit des règles d'affinité strictes qui doivent être remplies pour qu'un pod puisse être planifié sur un nœud. Le scheduler ne considère que les nœuds dont les labels correspondent à toutes les conditions spécifiées. Si aucun nœud correspondant n'est disponible, le pod reste en état Pending jusqu'à l'apparition d'un nœud adapté.

Ce type d'affinité est couramment utilisé pour les workloads ayant des exigences d'infrastructure strictes. Par exemple, une application de machine learning peut nécessiter des nœuds équipés de GPU, ou un workload sensible à la conformité peut devoir s'exécuter uniquement dans une région ou une zone de disponibilité donnée.

La partie IgnoredDuringExecution signifie que Kubernetes n'évince pas le pod si les labels du nœud changent après la planification. Si un label est supprimé ou modifié ultérieurement, le pod en cours d'exécution continue de fonctionner sur ce nœud, sauf si un autre mécanisme déclenche une replanification.

Exemple de code :

affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd

Dans cet exemple, le pod ne peut s'exécuter que sur des nœuds portant le label disktype=ssd.

2. PreferredDuringSchedulingIgnoredDuringExecution

preferredDuringSchedulingIgnoredDuringExecution définit des règles d'affinité souples qui influencent les décisions de planification sans les rendre obligatoires. Le scheduler tente de placer les pods sur des nœuds correspondant aux conditions préférées, mais peut toujours planifier le pod sur d'autres nœuds si nécessaire.

Les règles d'affinité préférées utilisent un système de pondération. Chaque préférence se voit attribuer un poids compris entre 1 et 100. Les nœuds correspondant aux préférences de poids plus élevé obtiennent un score supérieur lors de la planification, ce qui augmente leur probabilité d'être sélectionnés.

Cette approche est utile lorsque les préférences de placement améliorent les performances ou la maîtrise des coûts sans être strictement requises. Par exemple, vous pouvez préférer que les workloads s'exécutent sur des nœuds SSD ou dans une zone donnée pour réduire la latence, tout en autorisant la planification ailleurs en cas de pénurie de ressources.

Exemple de code :

affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd

Dans cet exemple, Kubernetes privilégie les nœuds portant le label disktype=ssd, mais le pod peut tout de même s'exécuter sur d'autres nœuds si aucun nœud SSD n'est disponible.

Cas d'usage courants de l'affinité de nœuds

Exécuter les workloads GPU sur des nœuds GPU

L'affinité de nœuds est utilisée pour exécuter des workloads GPU dans un cluster Kubernetes. En labellisant les nœuds équipés de GPU avec une clé telle que gpu=true, vous garantissez que les pods nécessitant des ressources GPU sont planifiés uniquement sur du matériel compatible. Cela évite la contention de ressources pour les workloads dépendant du GPU.

Une affinité souple peut être utilisée si un repli sur des nœuds CPU est acceptable dans les scénarios non critiques.

Planifier les bases de données sur des nœuds SSD

Les bases de données exigent souvent de hautes performances d'E/S, que les nœuds SSD peuvent fournir. En labellisant les nœuds avec disktype=ssd et en définissant une affinité de nœuds requise sur les pods de base de données, vous garantissez des performances de stockage élevées et une latence réduite pour les workloads stateful.

À mesure que de nouveaux nœuds SSD sont ajoutés et labellisés, les pods de base de données deviennent éligibles à la planification sur ces nœuds.

Maintenir les workloads dans une zone de disponibilité spécifique

Exécuter des workloads dans une zone de disponibilité spécifique peut réduire la latence, améliorer la tolérance aux pannes ou répondre à des exigences réglementaires. En labellisant les nœuds avec un identifiant de zone tel que zone=us-west1-b et en spécifiant une affinité de nœuds dans les spécifications des pods, vous contrôlez la répartition des pods entre les zones.

Avec une affinité préférée, vous pouvez orienter le scheduler vers la zone souhaitée tout en autorisant un repli vers d'autres zones si les ressources sont limitées.

Séparer les workloads de production et de développement

Séparer les environnements de production et de développement au sein d'un cluster partagé est un cas d'usage courant de l'affinité de nœuds. En labellisant les nœuds env=prod ou env=dev, vous pouvez appliquer des politiques de placement empêchant les workloads de développement de s'exécuter sur des nœuds de production, et inversement.

Avec une affinité requise, vous imposez une séparation stricte, tandis qu'une affinité préférée offre de la flexibilité en cas de ressources limitées.

Node affinity, node selector et pod affinity : les différences

L'affinité de nœuds, les node selectors et l'affinité de pods sont tous des mécanismes de planification Kubernetes, mais ils résolvent des problèmes de placement différents et offrent des niveaux de flexibilité variables.

Le node selector est l'option la plus simple. Il permet à un pod de s'exécuter uniquement sur des nœuds portant des labels spécifiques. Sa configuration est simple, avec des correspondances exactes clé-valeur telles que disktype=ssd. Cependant, nodeSelector ne prend en charge que de simples vérifications d'égalité et ne peut pas exprimer de conditions plus avancées, comme des valeurs multiples ou des règles d'exclusion.

L'affinité de nœuds étend les capacités de nodeSelector en prenant en charge des opérateurs de correspondance avancés tels que In, NotIn, Exists et DoesNotExist. Elle prend également en charge des règles de planification requises et préférées, offrant aux administrateurs davantage de contrôle sur le placement des pods. L'affinité de nœuds est généralement utilisée lorsque les workloads doivent cibler des nœuds ayant un matériel, des régions ou des rôles opérationnels spécifiques.

L'affinité de pods fonctionne différemment, car elle se concentre sur les relations entre pods plutôt que sur les labels de nœuds. Elle permet de planifier des pods à proximité d'autres pods portant des labels spécifiques, généralement au sein du même nœud ou de la même zone de disponibilité. C'est utile pour réduire la latence réseau entre services fortement couplés. Kubernetes prend également en charge l'anti-affinité de pods, qui répartit les pods pour améliorer la disponibilité et la tolérance aux pannes.

Le tableau suivant résume les principales différences :

Fonctionnalité Node selector Node affinity Pod affinity
Cible Labels de nœuds Labels de nœuds Autres pods
Complexité Simple Avancée Avancée
Opérateurs pris en charge Égalité uniquement Opérateurs multiples Sélecteurs de labels
Règles strictes et souples Non Oui Oui
Cas d'usage principal Sélection basique de nœuds Placement flexible sur les nœuds Co-localisation ou séparation de pods

Conseils de pro pour utiliser efficacement l'affinité de nœuds

1. Standardiser les labels de nœuds avant d'écrire des règles d'affinité

L'affinité de nœuds repose sur les labels de nœuds : une labellisation incohérente peut donc entraîner des échecs de planification ou un placement imprévisible des pods. Définissez une stratégie de labellisation claire avant de créer des politiques d'affinité. Utilisez des conventions de nommage cohérentes pour des labels tels que l'environnement, le type de matériel, la région, le rôle du workload ou la classe de stockage.

Par exemple, standardisez des labels comme env=prod, disktype=ssd ou workload=batch. Évitez de créer plusieurs labels représentant le même concept, comme gpu=true et accelerator=gpu.

Automatisez la gestion des labels dans la mesure du possible. Les fournisseurs cloud et les outils de provisionnement de clusters prennent souvent en charge la labellisation automatique des types d'instances, des zones et des node pools. L'automatisation réduit les erreurs de configuration manuelle et garantit la compatibilité des nouveaux nœuds avec les politiques d'affinité existantes.

2. Privilégier les règles souples, sauf si le placement est impératif

Les règles d'affinité strictes peuvent rendre des workloads non planifiables si aucun nœud correspondant n'est disponible. Un usage excessif de requiredDuringSchedulingIgnoredDuringExecution peut réduire la flexibilité du cluster lors des montées en charge, des fenêtres de maintenance ou des défaillances de nœuds.

Les règles d'affinité préférées offrent un comportement de planification plus résilient. Elles permettent à Kubernetes de privilégier les nœuds idéaux tout en plaçant les workloads ailleurs si nécessaire.

N'utilisez l'affinité stricte que lorsque le placement est impératif : applications dépendant du GPU, workloads soumis à des restrictions de licence, systèmes sensibles à la conformité ou applications nécessitant des fonctionnalités matérielles spécifiques.

3. Aligner l'affinité de nœuds sur l'autoscaling des nœuds

L'affinité de nœuds doit s'aligner sur les politiques d'autoscaling du cluster. Si les workloads nécessitent des nœuds avec des labels spécifiques, l'autoscaler doit pouvoir provisionner des groupes de nœuds correspondants. Sinon, les pods peuvent rester bloqués en état Pending, même avec l'autoscaling activé.

Par exemple, les workloads GPU doivent cibler des node pools dédiés aux instances GPU, tandis que les workloads gourmands en stockage doivent s'aligner sur des groupes de nœuds SSD.

Vérifiez que les limites de l'autoscaler couvrent la croissance attendue des workloads. Si l'autoscaler ne peut pas créer de nœuds correspondants supplémentaires en raison de quotas ou de contraintes de configuration, les règles d'affinité peuvent bloquer les déploiements.

4. Combiner l'affinité avec le right-sizing des workloads

L'affinité de nœuds est plus efficace lorsque les workloads sont correctement dimensionnés. Des requests CPU ou mémoire surdimensionnées peuvent limiter les options de planification, même si des nœuds adaptés correspondent aux règles d'affinité.

Par exemple, un pod avec des exigences d'affinité strictes et des requests mémoire excessives peut rester non planifié alors même que des nœuds correspondants existent.

Passez en revue les requests et limits de ressources des workloads en parallèle des politiques d'affinité. Les outils de monitoring et les métriques Kubernetes peuvent aider à identifier les workloads qui consomment systématiquement moins de ressources que demandé.

5. Réviser les politiques d'affinité à mesure que les workloads évoluent

Les exigences des infrastructures et des applications évoluent avec le temps : les politiques d'affinité de nœuds doivent donc être réexaminées régulièrement. Des labels autrefois pertinents peuvent devenir obsolètes après des mises à niveau du cluster, des migrations ou des changements d'architecture.

Des revues périodiques aident à identifier les contraintes inutiles, les labels non utilisés ou les politiques de planification qui réduisent l'efficacité du cluster.

Les revues opérationnelles doivent impliquer à la fois les équipes plateforme et applicatives, afin de s'assurer que les règles d'affinité correspondent toujours aux exigences des workloads sans ajouter de complexité de planification inutile.

Optimisez le placement des nœuds et l'efficacité des ressources avec PerfectScale

L'affinité de nœuds vous permet de contrôler où s'exécutent vos workloads, mais même des pods bien placés peuvent gaspiller de la capacité ou déclencher un scaling de nœuds superflu si leurs requests et limits de ressources sont mal calibrés. Les conteneurs surprovisionnés forcent l'autoscaler à créer plus de nœuds que nécessaire, les conteneurs sous-provisionnés provoquent des OOM kills et des évictions sur les nœuds pourtant soigneusement sélectionnés par vos règles d'affinité, et un bin-packing inefficace laisse les nœuds labellisés sous-utilisés. PerfectScale améliore l'efficacité de Kubernetes en effectuant un right-sizing autonome des workloads et en offrant une visibilité approfondie au niveau des nœuds, afin que vos politiques d'affinité placent les pods sur des nœuds déjà configurés pour une efficacité optimale.

Fonctionnalités clés de PerfectScale :

  • Right-sizing autonome des workloads : analyse en continu les workloads et ajuste les requests et limits CPU et mémoire en fonction de l'utilisation réelle, garantissant que les pods planifiés via des règles d'affinité utilisent les ressources efficacement.
  • Visibilité et optimisation au niveau des nœuds : offre une visibilité globale sur vos nœuds et node pools, valide les affinités de nœuds et les taints par rapport aux schémas réels de planification des workloads, et vous aide à choisir les types de nœuds optimaux pour chaque workload.
  • Correction proactive des configurations : identifie les erreurs de configuration — comme CPU Request Not Set, Memory Request Not Set et Memory Limit Not Set — qui provoquent des évictions, une surallocation des nœuds et une planification inefficace sur vos nœuds soigneusement labellisés.
  • Efficacité de l'autoscaling : affine les configurations des workloads afin que les autoscalers comme Karpenter et Cluster Autoscaler provisionnent les types et tailles de nœuds appropriés, pour un placement piloté par l'affinité qui reste prévisible et rentable.

Prêt à vous assurer que votre planification basée sur l'affinité place vos pods sur des nœuds efficaces et correctement dimensionnés ? Découvrez PerfectScale.

FAQ

Quelle est la différence entre affinité de nœuds stricte et souple ? Les règles strictes (requiredDuringSchedulingIgnoredDuringExecution) doivent être satisfaites, faute de quoi le pod reste en Pending. Les règles souples (preferredDuringSchedulingIgnoredDuringExecution) sont une préférence : le scheduler tente de les respecter, mais placera le pod ailleurs si nécessaire.

En quoi l'affinité de nœuds diffère-t-elle de nodeSelector ? nodeSelector ne prend en charge que des règles simples de correspondance exacte de labels. L'affinité de nœuds prend en charge des opérateurs plus riches (In, NotIn, Exists, DoesNotExist), ainsi qu'une logique de planification à la fois requise et préférée.

En quoi l'affinité de nœuds diffère-t-elle de l'affinité de pods ? L'affinité de nœuds associe les pods aux labels des nœuds. L'affinité de pods (et l'anti-affinité) associe les pods au placement d'autres pods, généralement pour co-localiser ou répartir des workloads liés.

Pourquoi mon pod reste-t-il en Pending alors qu'une affinité de nœuds est définie ? Généralement parce qu'aucun nœud ne correspond à une règle stricte (required) : vérifiez les labels des nœuds, assurez-vous que l'autoscaler peut provisionner des nœuds correspondants et confirmez que les requests de ressources du pod ne sont pas surdimensionnées pour les nœuds concernés.

Quand utiliser des règles strictes plutôt que des règles souples ? Uniquement lorsque le placement est réellement impératif : workloads dépendant du GPU, restrictions de licence ou exigences de conformité et de résidence des données. Sinon, privilégiez les règles souples pour conserver une planification flexible.

La modification des labels d'un nœud affecte-t-elle les pods déjà en cours d'exécution ? Non. Les règles étant IgnoredDuringExecution, un pod en cours d'exécution n'est pas évincé si les labels du nœud changent après sa planification.