## Introduction

Les règles d'affinité et d'anti-affinité des pods dans Kubernetes vous permettent de contrôler sur quels nœuds vos pods sont placés, en fonction des étiquettes des autres pods s'exécutant sur ces nœuds. C'est un outil puissant pour optimiser la latence, améliorer la résilience et imposer une colocalisation ou une séparation. Cependant, des erreurs de configuration conduisent souvent à des pods bloqués en état « Pending », à une planification inattendue ou à des inefficacités au niveau du cluster. Ce guide passe en revue les erreurs les plus courantes, comment les diagnostiquer et les corriger en toute sécurité avec des exemples pratiques.

## Inventaire des versions et de l'environnement

Avant de résoudre les problèmes d'affinité, établissez une base de référence de votre environnement. Vérifiez la version de Kubernetes, car la syntaxe et le comportement de l'affinité ont évolué. Utilisez `kubectl version --short` pour voir les versions client et serveur. Par exemple :

```bash
kubectl version --short
```

Sortie attendue (exemple) :

```
Client Version: v1.24.3
Server Version: v1.24.3
```

Remarque : Dans les versions plus récentes, `--short` est obsolète ; utilisez `kubectl version` sans drapeaux.

Ensuite, comprenez la topologie de votre cluster. Pour que l'affinité fonctionne, les nœuds doivent posséder les étiquettes pertinentes. Par exemple, pour une clé de topologie comme `topology.kubernetes.io/zone`, chaque nœud doit avoir une étiquette de zone. Listez les nœuds avec leurs étiquettes :

```bash
kubectl get nodes --show-labels
```

Recherchez des étiquettes telles que `kubernetes.io/hostname`, `topology.kubernetes.io/zone`, `topology.kubernetes.io/region` ou des étiquettes personnalisées comme `disktype=ssd`.

**Prérequis :**

- Un cluster avec au moins deux nœuds (pour démontrer l'anti-affinité).
- `kubectl` configuré avec accès au cluster.
- Compréhension des étiquettes et des sélecteurs.

## Chemin de configuration sûr

Commencez par un exemple minimal et testez dans un espace de noms non productif si possible. Nous créons ici un scénario : une application web et un cache qui doivent être colocalisés (affinité), et des réplicas web qui doivent être répartis sur les nœuds (anti-affinité).

### Exemple : Affinité de pods

Nous voulons qu'un pod web soit planifié sur un nœud qui exécute déjà un pod avec l'étiquette `app=cache`. Définissez le pod comme suit :

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname
  containers:
  - name: web
    image: nginx
```

Appliquez-le :

```bash
kubectl apply -f web-affinity.yaml
```

Si aucun pod cache n'existe, le pod web restera en état « Pending ». C'est une erreur courante : affinité non satisfaisable. Nous couvrirons le diagnostic plus tard.

### Exemple : Anti-affinité de pods

Pour répartir les pods web sur les nœuds, utilisez l'anti-affinité avec `topologyKey: kubernetes.io/hostname` :

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: web
            topologyKey: kubernetes.io/hostname
      containers:
      - name: web
        image: nginx
```

Cela garantit qu'aucun pod web de ce déploiement ne s'exécute sur le même nœud. Si vous avez moins de nœuds que de réplicas, les pods resteront en attente.

## Vérification et diagnostics

### Vérification du statut des pods

Pour voir si les pods ne peuvent pas être planifiés en raison de l'affinité, utilisez :

```bash
kubectl get pods
```

Recherchez les pods avec le statut `Pending`. Décrivez ensuite le pod :

```bash
kubectl describe pod <nom-du-pod>
```

Dans la section Événements, recherchez des messages comme :

```
Warning  FailedScheduling  2m (x25 over 5m)  default-scheduler  0/3 nodes are available: 1 node(s) didn't match pod affinity/anti-affinity, 2 node(s) didn't match pod anti-affinity rules.
```

Cela indique que le planificateur n'a pas trouvé de nœud satisfaisant les règles.

### Vérification des étiquettes des nœuds

Assurez-vous que toutes les clés de topologie utilisées dans vos règles d'affinité ont des étiquettes correspondantes sur les nœuds. Par exemple, si vous utilisez `topologyKey: topology.kubernetes.io/zone`, vérifiez les nœuds :

```bash
kubectl get nodes -L topology.kubernetes.io/zone
```

Si un nœud n'a pas l'étiquette, il ne sera pas pris en compte pour les pods utilisant cette clé de topologie.

### Simulation de planification

Il n'existe pas de simulation intégrée pour la planification, mais vous pouvez utiliser des outils comme le planificateur Kubernetes en mode débogage ou des validateurs tiers. Une vérification plus simple consiste à réduire temporairement le nombre de réplicas pour voir si un pod peut être planifié.

## Modes de défaillance et récupération

### Erreurs courantes et correctifs

- **Affinité de pods non satisfaisable** : Le pod requiert une étiquette qu'aucun pod existant n'a. Correctif : assurez-vous que le pod cible existe et possède la bonne étiquette. Exemple : avant d'appliquer `web-affinity.yaml`, créez un pod cache :

  ```yaml
  apiVersion: v1
  kind: Pod
  metadata:
    name: cache-pod
    labels:
      app: cache
  spec:
    containers:
    - name: redis
      image: redis
  ```

  Appliquez ensuite le pod web. Il devrait être planifié sur le même nœud.

- **Clé de topologie manquante sur les nœuds** : Si les nœuds n'ont pas l'étiquette de clé de topologie, les pods utilisant cette clé ne pourront pas être planifiés. Correctif : ajoutez l'étiquette aux nœuds :

  ```bash
  kubectl label nodes <nom-du-nœud> topology.kubernetes.io/zone=us-east-1a
  ```

- **Pas assez de nœuds pour l'anti-affinité** : Si vous exigez une anti-affinité avec `requiredDuringScheduling` et que vous avez plus de réplicas que de nœuds, certains pods resteront en attente. Correctif : augmentez le nombre de nœuds, utilisez `preferredDuringScheduling` pour une anti-affinité douce, ou réduisez le nombre de réplicas.

- **Incohérence du sélecteur d'étiquettes** : Assurez-vous que le sélecteur d'étiquettes dans l'affinité correspond aux étiquettes des pods que vous voulez attirer ou repousser. Utilisez `kubectl get pods --show-labels` pour vérifier.

- **Clé de topologie invalide** : Si la clé de topologie n'est pas une clé d'étiquette valide, le pod sera rejeté par le serveur d'API. Exemple : utiliser `topologyKey: "failure-domain.beta.kubernetes.io/zone"` qui est obsolète dans les versions plus récentes. Utilisez `topology.kubernetes.io/zone` à la place.

### Retour en arrière et récupération

Si une règle d'affinité cause une panne, supprimez ou modifiez la section d'affinité dans la spécification du pod. Pour un déploiement, mettez à jour le modèle de pod :

```bash
kubectl edit deployment web-deploy
```

Supprimez le bloc d'affinité ou modifiez-le. Supprimez ensuite les pods en attente pour forcer la recréation :

```bash
kubectl delete pods -l app=web
```

Pour un pod unique, supprimez-le et réappliquez sans affinité.

## Pièges courants et comment les éviter

### 1. Règles d'affinité trop restrictives

**Pourquoi cela arrive** : Utiliser `requiredDuringScheduling` avec des termes d'affinité complexes ou multiples peut rendre presque impossible pour le planificateur de trouver un nœud approprié. Par exemple, exiger à la fois une zone spécifique et une étiquette de nom d'hôte spécifique peut être insatisfaisable dans un petit cluster.

**Comment éviter** : Préférez `preferredDuringScheduling` pour les contraintes non critiques. Si vous devez utiliser `required`, testez d'abord dans un environnement de préproduction. Assurez-vous également que les clés de topologie que vous utilisez ont suffisamment de nœuds par domaine.

**Récupération** : Si les pods sont bloqués, modifiez le déploiement pour utiliser `preferredDuringScheduling` ou assouplissez le sélecteur. Supprimez les pods bloqués pour les replanifier.

### 2. Ignorer les étiquettes des nœuds

**Pourquoi cela arrive** : Supposer que les nœuds ont des étiquettes standard comme `topology.kubernetes.io/zone` alors qu'ils ne les ont pas, en particulier dans les clusters personnalisés ou sur site.

**Comment éviter** : Vérifiez toujours les étiquettes des nœuds avant d'écrire des règles d'affinité. Utilisez `kubectl get nodes --show-labels` et assurez-vous que les étiquettes requises sont présentes. Sinon, ajoutez-les manuellement ou via les étiquettes de nœuds dans votre infrastructure.

**Récupération** : Ajoutez les étiquettes manquantes aux nœuds en utilisant `kubectl label nodes`.

### 3. Oublier de mettre à jour les étiquettes lors du passage à l'échelle

**Pourquoi cela arrive** : Lorsque de nouveaux nœuds sont ajoutés au cluster, ils peuvent ne pas avoir les mêmes étiquettes personnalisées que les nœuds existants, ce qui entraîne un comportement de planification incohérent.

**Comment éviter** : Utilisez l'infrastructure comme code pour étiqueter automatiquement les nœuds, ou au moins ayez un runbook pour étiqueter les nouveaux nœuds.

**Récupération** : Étiquetez les nouveaux nœuds selon les besoins et supprimez les pods en attente pour les replanifier.

### 4. Confondre affinité de pods et affinité de nœuds

**Pourquoi cela arrive** : L'affinité de pods est basée sur les étiquettes d'autres pods, tandis que l'affinité de nœuds est basée sur les étiquettes des nœuds. Une mauvaise compréhension peut conduire à des sélecteurs et des clés de topologie incorrects.

**Comment éviter** : Comprenez clairement la différence : l'affinité de pods utilise `podAffinity` ou `podAntiAffinity` dans la spécification du pod et sélectionne des pods, tandis que l'affinité de nœuds utilise `nodeAffinity` et sélectionne des nœuds. Vérifiez toujours que le sélecteur correspond au type de ressource prévu.

**Récupération** : Examinez le YAML pour le bon type d'affinité et corrigez le sélecteur en conséquence.

### 5. Utiliser des clés de topologie obsolètes

**Pourquoi cela arrive** : La documentation et les exemples plus anciens peuvent encore utiliser des clés obsolètes comme `failure-domain.beta.kubernetes.io/zone` ou `beta.kubernetes.io/arch`.

**Comment éviter** : Tenez-vous-en aux étiquettes stables `topology.kubernetes.io/*`. L'étiquette `kubernetes.io/hostname` est toujours valide.

**Récupération** : Remplacez les clés obsolètes par les stables et réappliquez.

### 6. Ne pas tenir compte de la capacité de planification

**Pourquoi cela arrive** : Les règles d'anti-affinité requises limitent la densité des pods. Si vous avez plus de réplicas que de nœuds disponibles, certains pods ne seront jamais planifiés.

**Comment éviter** : Utilisez `preferredDuringScheduling` pour l'anti-affinité lorsque c'est possible, ou assurez-vous d'avoir suffisamment de nœuds pour satisfaire le nombre de réplicas. Envisagez d'utiliser des contraintes de répartition de la topologie des pods pour une répartition plus flexible.

**Récupération** : Réduisez le nombre de réplicas, ajoutez des nœuds ou passez à une anti-affinité préférée.

## Liste de contrôle opérationnelle

- Confirmez la version de Kubernetes et que les étiquettes existent sur les nœuds.
- Validez que les sélecteurs d'étiquettes dans les règles d'affinité correspondent aux étiquettes des pods existants.
- Assurez-vous que la clé de topologie est correcte et présente sur tous les nœuds concernés.
- Préférez `preferredDuringScheduling` pour les contraintes douces afin d'éviter les blocages durs.
- Surveillez les événements des pods pour détecter les échecs de planification.
- Testez les règles d'affinité dans un espace de noms de préproduction avant la production.
- Gardez les étiquettes des nœuds à jour, en particulier lors de l'ajout de nouveaux nœuds.
- Utilisez `kubectl describe` pour identifier rapidement les pods non planifiables et les raisons.
- Documentez vos politiques d'affinité pour référence par l'équipe.

## Conclusion

L'affinité et l'anti-affinité des pods sont précieuses pour contrôler le placement des pods, mais elles nécessitent une configuration soignée. En comprenant les erreurs courantes telles que les règles insatisfaisables, les étiquettes manquantes et les problèmes de clé de topologie, vous pouvez rapidement diagnostiquer et corriger les problèmes de planification. Commencez toujours par un test simple, vérifiez les étiquettes et envisagez d'utiliser des contraintes douces pour une meilleure résilience. Révisez régulièrement vos politiques de planification pour les aligner sur la capacité du cluster et les besoins des applications.