Qu'est-ce que l'affinité et l'anti-affinité des pods dans Kubernetes ?  – Informatique CloudSavvy
Agence web » Actualités du digital » Qu’est-ce que l’affinité et l’anti-affinité des pods dans Kubernetes ? – Informatique CloudSavvy

Qu’est-ce que l’affinité et l’anti-affinité des pods dans Kubernetes ? – Informatique CloudSavvy

Kubernetes est un système distribué conçu pour mettre à l’échelle des répliques de vos services dans plusieurs environnements physiques. Dans de nombreux cas, cela fonctionne bien dès le départ. Le planificateur Kubernetes place automatiquement vos pods (instances de conteneur) sur des nœuds (machines de travail) qui disposent de suffisamment de ressources pour les prendre en charge.

Malgré tous ses efforts, il arrive parfois que le planificateur ne sélectionne pas un plan avec lequel vous êtes d’accord. Vous voudrez peut-être que les pods soient colocalisés s’ils communiquent régulièrement sur le réseau ; alternativement, certains pods gourmands en calculs pourraient être mieux alloués à des nœuds séparés dans la mesure du possible.

Kubernetes dispose de plusieurs mécanismes qui vous permettent de guider le processus de prise de décision du planificateur afin que les pods se retrouvent sur des nœuds particuliers. Dans cet article, nous nous concentrerons spécifiquement sur les concepts « d’affinité » et « d’anti-affinité » qui vous donnent un contrôle granulaire de la planification. Les affinités définissent des règles qui doivent ou doivent être respectées avant qu’un pod puisse être alloué à un nœud.

Comment fonctionne l’affinité ?

Les affinités sont utilisées pour exprimer les contraintes de planification des pods qui peuvent correspondre aux caractéristiques des nœuds candidats et des pods qui s’exécutent déjà sur ces nœuds. Un pod qui a une « affinité » avec un nœud donné est plus susceptible d’y être programmé ; à l’inverse, une « anti-affinité » rend moins probable qu’elle soit programmée. L’équilibre global de ces poids est utilisé pour déterminer le placement final de chaque pod.

Les évaluations d’affinité peuvent produire des résultats concrets ou non. Un résultat « difficile » signifie que le nœud devoir ont les caractéristiques définies par l’expression d’affinité. Les affinités « soft » agissent comme une préférence, indiquant à l’ordonnanceur qu’il doit utiliser un nœud avec les caractéristiques s’il est disponible. Un nœud qui ne remplit pas la condition sera toujours sélectionné si nécessaire.

Types de condition d’affinité

Il existe actuellement deux types d’affinité différents que vous pouvez définir :

  • Affinité de nœud – Utilisé pour contraindre les nœuds pouvant recevoir un pod en faisant correspondre les étiquettes de ces nœuds. L’affinité de nœud ne peut être utilisée que pour définir des affinités positives qui attirent les pods vers le nœud.
  • Affinité inter-pods – Utilisé pour contraindre les nœuds pouvant recevoir un pod en faisant correspondre les étiquettes des pods existants déjà en cours d’exécution sur chacun de ces nœuds. L’affinité inter-pod peut être soit une affinité attractive, soit une anti-affinité répulsive.

Dans l’exemple le plus simple possible, un pod qui inclut une condition d’affinité de nœud de label=value ne sera planifié que pour les nœuds avec un label=value étiqueter. Un pod avec la même condition mais défini comme une affinité inter-pod sera programmé sur un nœud qui héberge déjà un Cosse avec un label=value étiqueter.

Définition des affinités de nœud

L’affinité de nœud a deux sous-types distincts :

  • requiredDuringSchedulingIgnoredDuringExecution – C’est le matcher d’affinité « dur » qui a besoin le nœud respecte les contraintes que vous définissez.
  • preferredDuringSchedulingIgnoredDuringExecution – Il s’agit du matcher « soft » pour exprimer une préférence qui est ignorée lorsqu’elle ne peut pas être satisfaite.

le IgnoredDuringExecution une partie de ces noms verbeux indique explicitement que l’affinité n’est prise en compte que lors de la planification des pods. Une fois qu’un pod est arrivé sur un nœud, l’affinité n’est pas réévaluée. Les modifications apportées au nœud n’entraîneront pas d’expulsion du pod en raison de la modification des valeurs d’affinité. Une future version de Kubernetes pourrait ajouter la prise en charge de ce comportement via le réservé requiredDuringSchedulingRequiredDuringExecution phrase.

Les affinités de nœud sont attachées aux pods via leur spec.affinity.nodeAffinity champ manifeste :

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
spec:
  containers:
    - name: demo-container
    # ...
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
            - key: hardware-class
              operator: In
              values:
                - a
                - b
                - c
          - matchExpressions:
            - key: internal
              operator: Exists

Ce manifeste crée une règle d’affinité stricte qui programme le pod sur un nœud répondant aux critères suivants :

  • Il a un hardware-class étiquette avec soit a, bou c comme valeur.
  • Il a un internal étiquette avec n’importe quelle valeur.

Vous pouvez joindre des conditions supplémentaires en répétant matchExpressions clause. Les opérateurs pris en charge pour les comparaisons de valeurs sont In, NotIn, Exists, DoesNotExist, Gt (supérieur à), et Lt (moins que).

le matchExpression clauses regroupées sous un même nodeSelectorTerms clause sont combinés avec un booléen AND. Ils doivent tous correspondre à un pod pour gagner en affinité avec un nœud particulier. Vous pouvez utiliser plusieurs nodeSelectorTerms clauses aussi; ceux-ci seront combinés comme une logique OR opération. Vous pouvez facilement assembler des critères de planification complexes en utilisant ces deux structures.

Les préférences de planification « soft » sont configurées de la même manière. Utiliser nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution à la place ou en plus de requiredDuringSchedulingIgnoredDuringExecution pour les configurer. Définissez chacune de vos contraintes facultatives comme un matchExpressions clause dans un preference champ:

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
spec:
  containers:
    - name: demo-container
    # ...
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: hardware-class
            operator: In
            values:
              - a
              - b
              - c

Les règles basées sur les préférences ont un champ supplémentaire appelé weight qui accepte un entier de 1 à 100. Chaque nœud qui correspond à une préférence a son poids d’affinité total incrémenté du montant défini ; le nœud qui se retrouve avec le poids global le plus élevé se verra attribuer le pod.

Définition des affinités inter-pods

Les affinités inter-pods fonctionnent de manière très similaire aux affinités de nœud, mais présentent des différences importantes. Les modes « hard » et « soft » sont indiqués par le même requiredDuringSchedulingIgnoredDuringExecution et preferredDuringSchedulingIgnoredDuringExecution des champs. Ceux-ci doivent être imbriqués sous le spec.affinity.podAffinity ou spec.affinity.podAntiAffinity champs selon que vous souhaitez augmenter ou réduire l’affinité du pod en cas de correspondance réussie.

Voici un exemple simple qui démontre à la fois l’affinité et l’anti-affinité :

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
spec:
  containers:
    - name: demo-container
    # ...
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: hardware-class
                operator: In
                values:
                  - a
                  - b
                  - c
          topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          podAffinityTerm:
            - labelSelector:
                matchExpressions:
                  - key: app-component
                    operator: In
                    values:
                      - background-worker
          topologyKey: topology.kubernetes.io/zone

Le format diffère légèrement de Node Affinity. Chaque matchExpressions contrainte doit être imbriquée sous un labelSelector. Pour les soft matches, celui-ci doit à son tour être situé dans un podAffinityTerm. Les affinités de pod offrent également un ensemble réduit d’opérateurs de comparaison : vous pouvez utiliser In, NotIn, Exists et DoesNotExist.

Les affinités de pod ont besoin d’un topologyKey champ. Ceci est utilisé pour limiter l’ensemble global de nœuds qui sont considérés comme éligibles pour la planification, avant la matchExpressions sont évalués. Les règles ci-dessus programmeront le pod sur un nœud avec le topology.kubernetes.io/zone label et un pod existant avec le hardware-class étiquette définie sur a, bou c. Les nœuds qui ont également un pod avec le app-component=background-worker l’étiquette recevra une affinité réduite.

Les affinités inter-pods sont un mécanisme puissant pour contrôler la colocation des pods. Cependant, ils ont un impact significatif sur les performances : Kubernetes met en garde contre leur utilisation dans des clusters de plus de quelques centaines de nœuds. Chaque nouvelle demande de planification de pod doit vérifier tous les autres pods sur tous les autres nœuds pour évaluer la compatibilité.

Autres contraintes de planification

Bien que nous nous soyons concentrés sur les affinités dans cet article, Kubernetes fournit également d’autres mécanismes de contrainte de planificateur. Il s’agit généralement d’approches plus simples mais moins automatisées qui fonctionnent bien pour les clusters et les déploiements plus petits.

La contrainte la plus fondamentale est la nodeSelector champ. Il est défini sur les pods comme un ensemble de paires clé-valeur d’étiquette qui doivent exister sur les nœuds hébergeant le pod :

apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  containers:
    - name: demo
      # ...
  nodeSelector:
    hardware-class: a
    internal: true

Ce manifeste indique à Kubernetes de planifier uniquement le pod vers les nœuds avec à la fois le hardware-class: a et internal: true Étiquettes.

Sélection de nœud avec le nodeSelector est un bon moyen d’échafauder rapidement une configuration statique basée sur les attributs de longue durée de vos nœuds. Le système d’affinité est beaucoup plus flexible lorsque vous souhaitez exprimer des règles complexes et des préférences facultatives.

Conclusion

Les affinités et les anti-affinités sont utilisées pour configurer des contraintes de planification de pod polyvalentes dans Kubernetes. Par rapport à d’autres options comme nodeSelectorles affinités sont complexes mais vous offrent plus de moyens d’identifier les nœuds compatibles.

Les affinités peuvent agir comme des préférences souples qui signalent l’environnement « idéal » d’un pod à Kubernetes, même s’il ne peut pas être immédiatement satisfait. Le système a également la capacité unique de filtrer les nœuds en fonction de leurs charges de travail existantes afin que vous puissiez mettre en œuvre des règles de colocation de pod.

Un dernier point à noter est que l’affinité n’est pas la fin du processus de planification. Un pod avec une forte affinité calculée avec un nœud peut toujours se retrouver ailleurs en raison de l’entrée de rejets de nœud. Ce mécanisme vous permet de gérer les demandes de planification du point de vue de vos nœuds. Les souillures repoussent activement les pods entrants vers d’autres nœuds, en fait à l’opposé de l’attraction magnétique des affinités. Les sélecteurs de nœuds, les affinités, les rejets et les tolérances sont tous équilibrés pour déterminer l’emplacement final dans le cluster de chaque nouveau pod.

★★★★★