Contactez-nous

Colocation et séparation des Pods : Pod Affinity et Anti-Affinity

Découvrez comment utiliser Pod Affinity et Anti-Affinity dans Kubernetes pour contrôler la colocation ou la séparation de vos Pods, optimisant performance et haute disponibilité.

Au-delà du noeud : contrôler les relations entre Pods

Après avoir exploré comment influencer le placement des Pods par rapport aux caractéristiques des Noeuds (via Node Affinity) ou comment repousser les Pods de certains Noeuds (via Taints/Tolerations), nous abordons maintenant une autre dimension de l'ordonnancement avancé : le contrôle du placement des Pods les uns par rapport aux autres. Dans de nombreux scénarios, il est souhaitable, voire nécessaire, que certains Pods soient placés à proximité les uns des autres, ou au contraire, qu'ils soient maintenus séparés.

Par exemple, pour des raisons de performance, vous pourriez vouloir colocaliser un Pod applicatif avec son Pod de cache sur le même noeud pour minimiser la latence réseau. Inversement, pour des raisons de haute disponibilité, vous voudrez probablement vous assurer que les différents réplicas d'une application critique (comme un StatefulSet) sont répartis sur des noeuds ou des zones de disponibilité différents pour éviter qu'une défaillance unique n'affecte tous les réplicas.

Kubernetes répond à ces besoins grâce à deux mécanismes puissants : Pod Affinity (pour la colocation) et Pod Anti-Affinity (pour la séparation). Ces règles sont définies dans la spécification du Pod et influencent directement les décisions du Scheduler.

Pod Affinity : rapprocher les Pods

Pod Affinity (Affinité de Pod) est utilisé pour indiquer au Scheduler qu'un Pod devrait être ordonnancé sur un noeud où se trouvent déjà d'autres Pods correspondant à certains critères (basés sur leurs labels). L'objectif est la colocation.

Comme pour Node Affinity, Pod Affinity se décline en deux types :

  • requiredDuringSchedulingIgnoredDuringExecution : Règle d'affinité requise. Le Pod ne sera ordonnancé que s'il existe un noeud approprié hébergeant déjà au moins un Pod correspondant au critère.
  • preferredDuringSchedulingIgnoredDuringExecution : Règle d'affinité préférée. Le Scheduler essaiera de trouver un noeud satisfaisant la condition de colocation, mais placera le Pod ailleurs si ce n'est pas possible. Des poids (weight) sont utilisés pour indiquer la force de la préférence.

La configuration se fait via spec.affinity.podAffinity et implique deux éléments clés :

  • labelSelector : Identifie les Pods cibles (ceux avec lesquels on souhaite être colocalisé) en se basant sur leurs labels.
  • topologyKey : Définit le 'domaine' de colocation. C'est une clé de label de noeud. La règle d'affinité s'applique uniquement aux Pods situés sur des noeuds partageant la même valeur pour cette clé de label que le noeud candidat. Typiquement, on utilise kubernetes.io/hostname pour une colocation sur le même noeud, ou topology.kubernetes.io/zone pour une colocation dans la même zone de disponibilité.

Exemple : Exiger que ce Pod soit placé sur un noeud où s'exécute déjà un Pod ayant le label `service=backend`.

apiVersion: v1
kind: Pod
metadata:
  name: web-server
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: service
            operator: In
            values:
            - backend
        topologyKey: kubernetes.io/hostname # Doit être sur le MEME noeud
  containers:
  - name: web-app
    image: web-app

Exemple : Préférer être dans la même zone que des Pods ayant `app=database`.

apiVersion: v1
kind: Pod
metadata:
  name: reporting-app
spec:
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - database
          topologyKey: topology.kubernetes.io/zone # Préfère la MEME zone
  containers:
  - name: reporting
    image: reporting

Pod Anti-Affinity : séparer les Pods

Pod Anti-Affinity (Anti-Affinité de Pod) est utilisé pour indiquer au Scheduler qu'un Pod ne devrait pas être ordonnancé sur un noeud où se trouvent déjà d'autres Pods correspondant à certains critères. L'objectif est la séparation pour améliorer la haute disponibilité ou éviter les interférences.

Elle suit exactement la même structure que Pod Affinity, avec les types requiredDuringScheduling... et preferredDuringScheduling..., et utilise également labelSelector pour identifier les Pods à éviter et topologyKey pour définir le domaine de séparation.

Exemple : Exiger que ce Pod ne soit PAS placé sur un noeud où s'exécute déjà un Pod ayant le label `app=critical-replica` (pour un StatefulSet par exemple).

apiVersion: apps/v1
kind: StatefulSet
# ... autres métadonnées et spec du StatefulSet ...
spec:
  selector:
    matchLabels:
      app: critical-replica # Label des Pods du StatefulSet
  serviceName: "my-critical-service"
  replicas: 3
  template:
    metadata:
      labels:
        app: critical-replica # Le Pod lui-même a ce label
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - critical-replica # Ne pas être avec d'autres Pods ayant ce label
            topologyKey: kubernetes.io/hostname # Ne pas être sur le MEME noeud
      containers:
      - name: critical-app
        image: critical-app

Exemple : Préférer fortement ne pas être dans la même zone qu'un autre Pod du même déploiement (label `app=my-stateless-app`).

apiVersion: apps/v1
kind: Deployment
# ...
spec:
  replicas: 5
  selector:
     matchLabels:
       app: my-stateless-app
  template:
    metadata:
      labels:
        app: my-stateless-app
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - my-stateless-app
              topologyKey: topology.kubernetes.io/zone # Préférer NE PAS être dans la même zone
      containers:
      - name: stateless-worker
        image: stateless-worker

Le rôle crucial de `topologyKey`

Le choix de topologyKey est absolument fondamental car il définit la portée de la règle d'affinité ou d'anti-affinité. Il s'agit d'une clé de label présente sur les noeuds. Le Scheduler regroupe les noeuds ayant la même valeur pour cette clé.

  • kubernetes.io/hostname : La règle s'applique au niveau du noeud individuel. Pod Affinity avec cette clé signifie 'sur le même noeud'. Pod Anti-Affinity signifie 'pas sur le même noeud'. C'est le niveau le plus granulaire.
  • topology.kubernetes.io/zone : La règle s'applique au niveau de la zone de disponibilité (si votre cluster est configuré pour connaître les zones, ce qui est courant dans le cloud). Pod Affinity signifie 'dans la même zone'. Pod Anti-Affinity signifie 'pas dans la même zone'. Utile pour la haute disponibilité inter-zones.
  • topology.kubernetes.io/region : La règle s'applique au niveau de la région (moins courant pour l'anti-affinité, car souvent trop large).
  • Labels personnalisés : Vous pouvez utiliser n'importe quel label personnalisé présent sur vos noeuds comme topologyKey (par exemple, `rack`, `power-circuit`, `node-pool`) pour définir des domaines de colocation/séparation spécifiques à votre infrastructure.

Le choix de la `topologyKey` dépend directement de l'objectif recherché : latence minimale (hostname pour Pod Affinity), haute disponibilité face à une panne de noeud (hostname pour Pod Anti-Affinity), ou haute disponibilité face à une panne de zone (topology.kubernetes.io/zone pour Pod Anti-Affinity).

Cas d'usage et considérations importantes

Cas d'usage typiques :

  • Pod Affinity (hostname) : Colocaliser un serveur web et un cache local (Redis, Memcached), ou un agent de logging/monitoring avec l'application qu'il surveille.
  • Pod Anti-Affinity (hostname) : Répartir les réplicas d'un StatefulSet (base de données, Zookeeper...) sur différents noeuds pour survivre à une panne de noeud. Empêcher deux Pods très consommateurs de ressources de se retrouver sur le même noeud.
  • Pod Anti-Affinity (zone) : Répartir les réplicas d'un Deployment ou StatefulSet critique sur différentes zones de disponibilité pour survivre à une panne de zone complète.

Considérations :

  • Performance du Scheduler : Les règles d'affinité/anti-affinité de Pods peuvent être coûteuses en termes de calcul pour le Scheduler, surtout dans les grands clusters avec de nombreux Pods. Elles nécessitent d'évaluer les relations entre les Pods sur chaque noeud candidat. Utilisez-les judicieusement.
  • Combinaison avec d'autres règles : Ces règles interagissent avec Node Affinity, Taints/Tolerations et les besoins en ressources. Une combinaison complexe de règles peut rendre difficile l'ordonnancement d'un Pod.
  • Attention aux règles requises : Une règle requiredDuringScheduling... trop stricte (surtout en Anti-Affinity) peut empêcher un Pod d'être ordonnancé si aucune topologie ne peut satisfaire la contrainte (par exemple, demander plus de réplicas qu'il n'y a de noeuds/zones disponibles pour l'anti-affinité). Privilégiez les règles preferredDuringScheduling... lorsque la séparation/colocation est souhaitable mais pas absolument bloquante.
  • Labels : L'efficacité de ces mécanismes dépend entièrement d'une stratégie de labellisation cohérente pour vos Pods.

En maîtrisant Pod Affinity et Anti-Affinity, vous ajoutez une corde essentielle à votre arc pour concevoir des déploiements Kubernetes performants, résilients et adaptés aux exigences spécifiques de vos applications et de votre infrastructure.