E-NO
Kubernetes 8 min de lecture

Contraintes de répartition topologique Kubernetes : concepts avancés et mise en œuvre pratique

calendar_today Publié : 2026-08-25
update Dernière mise à jour : 2026-08-25
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Contraintes de répartition topologique Kubernetes : concepts avancés et mise en œuvre pratique ».

Introduction

Les contraintes de répartition topologique Kubernetes (Topology Spread Constraints) sont une fonctionnalité puissante de planification qui garantit que les pods sont répartis uniformément dans les domaines topologiques de votre cluster, tels que les zones, les régions ou les nœuds. Si le concept de base est simple, une utilisation avancée implique des interactions nuancées avec l'affinité de nœuds, l'anti-affinité de pods, les nœuds non planifiables et la mise à l'échelle automatique du cluster. Cet article explore en profondeur les mécanismes, fournit des exemples pratiques avec les sorties attendues et vous prépare à résoudre les modes de défaillance courants.

À la fin, vous comprendrez comment configurer les contraintes pour une haute disponibilité, éviter les blocages de planification et vérifier efficacement votre configuration.

Inventaire des versions et de l'environnement

Avant de travailler avec les contraintes de répartition topologique, vérifiez votre version Kubernetes et les capacités de l'environnement. Les contraintes de répartition topologique sont stables depuis la v1.19 et continuent d'évoluer. Vérifiez la version de votre serveur :

kubectl version --short

Sortie attendue (exemple) :

Client Version: v1.27.3
Kustomize Version: v5.0.1
Server Version: v1.27.3

Assurez-vous que la porte de fonctionnalité EvenPodsSpread est activée (par défaut depuis v1.18) et que vos nœuds ont des étiquettes appropriées pour les clés de topologie. Les clés courantes incluent :

  • topology.kubernetes.io/zone
  • topology.kubernetes.io/region
  • kubernetes.io/hostname

Listez les étiquettes des nœuds pour confirmer :

kubectl get nodes --show-labels

Extrait d'exemple :

NAME      STATUS   ROLES    AGE   VERSION   LABELS
node-1    Ready    <none>   10d   v1.27.3   kubernetes.io/hostname=node-1,topology.kubernetes.io/zone=us-east-1a,topology.kubernetes.io/region=us-east-1
node-2    Ready    <none>   10d   v1.27.3   kubernetes.io/hostname=node-2,topology.kubernetes.io/zone=us-east-1b,topology.kubernetes.io/region=us-east-1
node-3    Ready    <none>   10d   v1.27.3   kubernetes.io/hostname=node-3,topology.kubernetes.io/zone=us-east-1c,topology.kubernetes.io/region=us-east-1

Pour un test pratique, commencez par un déploiement minimal et observez son comportement de planification avant d'ajouter des contraintes.

Observation en lecture seule

Avant d'apporter des modifications, capturez l'état actuel de la planification :

kubectl get pods -o wide

Sortie d'exemple :

NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
nginx-7d9b7456c4-abcde   1/1     Running   0          5m    10.244.1.5   node-1   <none>           <none>
nnginx-7d9b7456c4-fghij   1/1     Running   0          5m    10.244.2.10  node-2   <none>           <none>
nnginx-7d9b7456c4-klmno   1/1     Running   0          5m    10.244.3.7   node-3   <none>           <none>

Cela montre que les pods sont répartis uniformément entre les nœuds par hasard, mais sans garantie.

Question rapide 1 sur 2

Que spécifie le champ « minDomains » dans une contrainte de répartition topologique ?

Le passage de référence [5] indique : « minDomains indique un nombre minimal de domaines éligibles. Un domaine est une instance particulière d’une topologie. Un domaine éligible est un domaine dont les nœuds correspondent au sélecteur de nœuds. »

Chemin de configuration sûr

Comprendre l'objet de contrainte

Une contrainte de répartition topologique est définie dans la spécification du pod. Voici un exemple de base réparti entre les zones :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: web
      containers:
      - name: nginx
        image: nginx:1.25

Appliquez-le :

kubectl apply -f web-deployment.yaml

Vérifiez la répartition :

kubectl get pods -o wide --selector=app=web

Sortie d'exemple :

NAME                  READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
web-7d9b7456c4-abcde  1/1     Running   0          10s   10.244.1.6   node-1   <none>           <none>
web-7d9b7456c4-fghij  1/1     Running   0          10s   10.244.2.11  node-2   <none>           <none>
web-7d9b7456c4-klmno  1/1     Running   0          10s   10.244.3.8   node-3   <none>           <none>

Ici, chaque pod a atterri dans une zone différente, satisfaisant maxSkew: 1.

Paramètres avancés

maxSkew est la différence maximale autorisée dans le nombre de pods entre deux domaines topologiques. Elle doit être supérieure à zéro.

whenUnsatisfiable peut être DoNotSchedule (strict) ou ScheduleAnyway (souple). Avec DoNotSchedule, si la contrainte ne peut pas être satisfaite, le pod reste en attente. Avec ScheduleAnyway, le planificateur le place quand même, mais le déséquilibre peut être violé.

minDomains (bêta en v1.25) spécifie un nombre minimum de domaines éligibles. Le planificateur ne planifiera pas si moins de domaines sont disponibles, même si le déséquilibre est satisfait. Cela est utile pour garantir la disponibilité lors de pannes de zones.

Exemple avec minDomains :

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone
  whenUnsatisfiable: DoNotSchedule
  minDomains: 3   # nécessite au moins 3 zones
  labelSelector:
    matchLabels:
      app: web

Interaction avec l'affinité de nœuds et l'anti-affinité

Les contraintes de répartition topologique fonctionnent avec l'affinité de nœuds et l'anti-affinité de pods, mais l'effet combiné peut être complexe. Le planificateur prend en compte toutes les contraintes, et la plus restrictive domine.

Exemple combinant avec l'affinité de nœuds :

Supposons que vous vouliez répartir les pods entre les zones mais uniquement sur des nœuds avec SSD. Ajoutez une affinité de nœuds :

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

Désormais, les pods ne seront planifiés que sur des nœuds avec disktype=ssd, puis répartis entre les zones de ces nœuds.

Interaction avec l'anti-affinité de pods :

L'anti-affinité de pods peut empêcher la colocalisation des pods. Si la répartition et l'anti-affinité sont définies, les règles d'anti-affinité peuvent prévaloir sur les contraintes de répartition. Par exemple, si l'anti-affinité exige que chaque pod soit sur un nœud différent, et que la répartition veut maxSkew=1 entre les zones, le planificateur doit satisfaire les deux. Comprenez ces priorités pour éviter des pods en attente inattendus.

Vérification et diagnostics

Observer la répartition avec des commandes

Après avoir appliqué un déploiement avec des contraintes de répartition, vérifiez la distribution réelle :

kubectl get pods -o wide -l app=web

Comptez les pods par nœud ou zone :

kubectl get pods -l app=web -o json | jq -r '.items[].spec.nodeName' | sort | uniq -c

Sortie d'exemple :

1 node-1
1 node-2
1 node-3

Pour inspecter la contrainte sur un pod en cours d'exécution :

kubectl get pod web-7d9b7456c4-abcde -o yaml | grep -A 10 topologySpreadConstraints

Diagnostiquer les pods en attente

Si les pods restent en attente, décrivez-les :

kubectl describe pod web-7d9b7456c4-abcde

Recherchez des événements comme :

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  2m    default-scheduler  0/3 nodes are available: 3 node(s) didn't match topology spread constraints.

Cela indique que la contrainte ne peut pas être satisfaite avec la topologie actuelle des nœuds.

Vérifiez les décisions de planification à l'aide des journaux de débogage du planificateur si nécessaire :

kubectl logs -n kube-system kube-scheduler-<master-node> | grep -i spread

Question rapide 2 sur 2

Que se passe-t-il si l’intersection de plusieurs contraintes de répartition topologique renvoie un ensemble vide ?

Le passage de référence [4] montre que si l’intersection des contraintes renvoie un ensemble vide, le planificateur ne peut pas placer le pod, le laissant à l’état Pending.

Modes de défaillance et récupération

Scénario 1 : Domaines insuffisants

Si vous avez moins de domaines topologiques que requis par minDomains ou que maxSkew ne peut pas être satisfait, les pods seront en attente. Exemple : vous demandez une répartition entre les zones avec minDomains: 3, mais il n'existe que deux zones. Le planificateur ne placera aucun pod.

Récupération :

  • Réduisez minDomains à 2 ou supprimez-le.
  • Augmentez maxSkew pour permettre une répartition inégale.
  • Ajoutez des nœuds dans de nouvelles zones.
  • Changez temporairement whenUnsatisfiable en ScheduleAnyway pour une contrainte souple.

Scénario 2 : Violation du déséquilibre après mise à l'échelle

Si vous réduisez puis augmentez l'échelle, le déséquilibre peut dépasser maxSkew. Le planificateur tente de rééquilibrer, mais il n'évince pas les pods. De nouveaux pods peuvent être planifiés pour réduire le déséquilibre, mais les pods existants restent. Avec le temps, le déséquilibre peut se normaliser.

Exemple :

Initialement : 3 pods dans 3 zones, déséquilibre=0. Réduisez à 1 pod, qui reste dans la zone-1. Augmentez à 3 : le planificateur voit que la zone-1 a 1 pod, les autres 0. Pour maintenir maxSkew=1, il place un pod dans la zone-2 et un dans la zone-3. Le résultat est à nouveau un pod par zone.

Si vous passez à 4 réplicas, avec maxSkew=1, le planificateur peut placer deux pods dans une zone et un dans chacune des autres, ce qui donne un déséquilibre=1 (acceptable).

Scénario 3 : Interaction avec l'autoscaler de cluster

Les contraintes de répartition topologique peuvent empêcher l'autoscaler de cluster de monter en charge correctement. Si un pod est non planifiable en raison des contraintes de répartition, l'autoscaler peut ne pas savoir quel groupe de nœuds mettre à l'échelle. Pour éviter cela, assurez-vous que les groupes de nœuds correspondent aux zones topologiques et utilisez topologySpreadConstraints avec ScheduleAnyway ou fiez-vous à l'anti-affinité de pods.

Scénario 4 : Répartition topologique des pods avec sélecteur de nœuds

Si un sélecteur de nœuds limite la planification à un sous-ensemble de nœuds, le planificateur ne considère que ces nœuds pour la répartition. Cela peut entraîner un déséquilibre. Par exemple, si le sélecteur de nœuds ne sélectionne que des nœuds dans la zone A, tous les pods y vont indépendamment de la répartition. Assurez-vous que les sélecteurs s'alignent sur les domaines topologiques.

Liste de contrôle des opérations

Utilisez cette liste de contrôle pour implémenter et exploiter en toute sécurité les contraintes de répartition topologique :

ÉtapeActionCommande / VérificationExemple
1Vérifier la version Kubernetes et les portes de fonctionnalitékubectl version --shortServeur v1.27+, EvenPodsSpread activé
2Inspecter les étiquettes de topologie des nœudskubectl get nodes --show-labelsLes nœuds ont des étiquettes topology.kubernetes.io/zone
3Appliquer un déploiement de test sans contrainteskubectl apply -f test.yamlLes pods se planifient normalement
4Ajouter des contraintes de répartition à une copieModifier le manifeste, puis kubectl apply -f constrained.yamlLes pods se répartissent comme prévu
5Vérifier la distribution réellekubectl get pods -o wide -l app=testPods répartis uniformément entre les zones
6Tester les scénarios de défaillanceRéduire/augmenter l'échelle, simuler une perte de zoneObserver le déséquilibre et le comportement en attente
7Documenter le plan de retour en arrièreConserver le manifeste d'origine : kubectl apply -f original.yamlPrêt à revenir en arrière si des problèmes surviennent
8Surveiller dans le tempskubectl get pods -o wide périodiquement ou utiliser kube-state-metricsLe déséquilibre reste dans les limites

Exemple concret : application web multi-zones

Parcourons un exemple complet pour une application web de type production avec 6 réplicas répartis sur 3 zones, avec maxSkew=1 et DoNotSchedule.

  1. Étiquetez les nœuds (si ce n'est pas déjà fait) :
   kubectl label node node-1 topology.kubernetes.io/zone=us-east-1a
   kubectl label node node-2 topology.kubernetes.io/zone=us-east-1b
   kubectl label node node-3 topology.kubernetes.io/zone=us-east-1c
  1. Créez un namespace :
   kubectl create namespace webapp
  1. Définissez le manifeste de déploiement webapp-deployment.yaml :
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: webapp
     namespace: webapp
   spec:
     replicas: 6
     selector:
       matchLabels:
         app: webapp
     template:
       metadata:
         labels:
           app: webapp
       spec:
         topologySpreadConstraints:
         - maxSkew: 1
           topologyKey: topology.kubernetes.io/zone
           whenUnsatisfiable: DoNotSchedule
           labelSelector:
             matchLabels:
               app: webapp
         containers:
         - name: app
           image: nginx:1.25
           ports:
           - containerPort: 80
  1. Appliquez et attendez :
   kubectl apply -f webapp-deployment.yaml
   kubectl rollout status deployment/webapp -n webapp
  1. Vérifiez la distribution :
   kubectl get pods -n webapp -o wide -l app=webapp

Sortie attendue : 2 pods par zone, tous en cours d'exécution.

  1. Vérifiez le déséquilibre à l'aide d'un petit script :
   kubectl get pods -n webapp -l app=webapp -o json | jq -r '.items[] | .spec.nodeName' | \
   xargs -I {} kubectl get node {} --show-labels | grep topology.kubernetes.io/zone | \
   awk -F'topology.kubernetes.io/zone=' '{print $2}' | cut -d',' -f1 | sort | uniq -c

Sortie d'exemple :

   2 us-east-1a
   2 us-east-1b
   2 us-east-1c
  1. Simulez une panne de zone en cordonnant les nœuds d'une zone :
   kubectl cordon node-1   # en supposant que node-1 est dans us-east-1a

Les pods existants continuent de fonctionner. Si vous passez à 9 réplicas, le planificateur placera les nouveaux pods dans les deux zones restantes, mais ne dépassera peut-être pas maxSkew de 1 si possible. Cependant, avec seulement deux zones, le déséquilibre maximal peut encore être de 1 si la répartition est égale.

  1. Décordonnez pour restaurer :
   kubectl uncordon node-1

Cette liste de contrôle et cet exemple démontrent la préparation opérationnelle.

Conclusion

Les contraintes de répartition topologique Kubernetes offrent un contrôle fin sur la distribution des pods, améliorant la disponibilité et l'utilisation des ressources. En comprenant les paramètres et les interactions avec d'autres fonctionnalités de planification, vous pouvez concevoir des déploiements multi-zones robustes. Vérifiez toujours avec des commandes réelles, anticipez les modes de défaillance et ayez un plan de retour en arrière. Commencez par un petit test, observez le comportement du planificateur et montez en charge en toute confiance.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO