Tous les produits
Search
Centre de documentation

Container Service for Kubernetes:Spread ECI pods across zones and configure affinity scheduling

Dernière mise à jour :Aug 11, 2026

Lorsque la création de pods basés sur ECI échoue dans une zone, tous les réplicas concentrés dans cette zone deviennent indisponibles. Deux scénarios d'échec sont courants : tous les réplicas se retrouvent dans la même zone lors de la planification, et les échecs de création ECI dans certaines zones violent silencieusement les garanties de répartition. Cette rubrique explique comment utiliser les contraintes de répartition topologique Kubernetes et les règles d'affinité pour prévenir ces deux problèmes dans un cluster ACK managé Pro.

Prérequis

Avant de commencer, assurez-vous de disposer des éléments suivants :

  • Un cluster ACK managé Pro répondant aux exigences suivantes :

  • Plusieurs zones (vSwitch) configurées dans le profil eci-profile afin que les pods puissent être planifiés entre les zones

  • Les champs nodeAffinity, podAffinity ou topologySpreadConstraints définis dans la spécification de votre pod, ou une ResourcePolicy configurée pour le pod

Remarque

Pour planifier des pods sur des nœuds virtuels basés sur ARM, ajoutez des tolérations correspondant aux taints de ces nœuds.

Notes d'utilisation

  • Définissez topologyKey sur topology.kubernetes.io/zone.

  • Le comportement de planification décrit dans cette rubrique ne s'applique pas lorsque :

    • L'annotation k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered" est définie sur le pod (la planification multi-zones suit alors un ordre fixe de vSwitch).

    • L'annotation k8s.aliyun.com/eci-fail-strategy: "fail-fast" est définie sur le pod.

Choisir une approche

Deux mécanismes Kubernetes répondent à des objectifs différents :

Objectif Mécanisme Cas d'utilisation
Répartir les pods uniformément entre toutes les zones disponibles topologySpreadConstraints Haute disponibilité — les réplicas sont distribués de sorte qu'une défaillance d'une seule zone n'affecte qu'une fraction d'entre eux
Épingler les pods à une zone spécifique ou les maintenir colocalisés podAffinity + nodeAffinity Performance — la faible latence entre les pods est cruciale, ou votre charge de travail doit se trouver dans une zone particulière

Les deux exemples ci-dessous utilisent les mêmes champs requis par ECI : une tolération pour virtual-kubelet.io/provider et une affinité de nœud preferredDuringSchedulingIgnoredDuringExecution qui privilégie les nœuds Elastic Compute Service (ECS) par rapport aux nœuds virtuels. Seule la règle de répartition ou d'affinité change.

Exemple 1 : Répartir les pods uniformément entre les zones

Cet exemple crée un Deployment avec 10 réplicas répartis uniformément entre toutes les zones disponibles.

Étape 1 : Créer le Deployment

Enregistrez le code YAML suivant dans le fichier deployment.yaml et exécutez la commande kubectl apply -f deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: with-pod-topology-spread
  labels:
    app: with-pod-topology-spread
spec:
  replicas: 10
  selector:
    matchLabels:
      app: with-pod-topology-spread
  template:
    metadata:
      labels:
        app: with-pod-topology-spread
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: type
                operator: NotIn
                values:
                - virtual-kubelet
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: with-pod-topology-spread
      tolerations:
        - key: "virtual-kubelet.io/provider"
          operator: "Exists"
          effect: "NoSchedule"
      containers:
      - name: with-pod-topology-spread
        image: registry.k8s.io/pause:2.0
        resources:
          requests:
            cpu: "1"
            memory: "256Mi"

Les trois sections pertinentes pour la planification sont :

Section Fonction
nodeAffinity (preferredDuringSchedulingIgnoredDuringExecution, type NotIn virtual-kubelet) Privilégie les nœuds ECS ; bascule sur les nœuds virtuels lorsqu'aucun nœud ECS n'est disponible. Consultez la section Node affinity.
topologySpreadConstraints (maxSkew: 1, topologyKey: topology.kubernetes.io/zone, whenUnsatisfiable: DoNotSchedule) Maintient la différence du nombre de pods entre deux zones quelconques à 1 au maximum. kube-scheduler bloque le placement si cette contrainte ne peut pas être satisfaite. Consultez le champ topologySpreadConstraints field.
tolerations (virtual-kubelet.io/provider: Exists, NoSchedule) Permet à kube-scheduler de placer des pods sur des nœuds virtuels, qui portent ce taint par défaut. Consultez la section Taints and tolerations.
Remarque

Pour planifier des pods sur des nœuds virtuels basés sur ARM, ajoutez une tolération pour le taint spécifique à ARM.

Le champ topologySpreadConstraints accepte plusieurs paramètres. Le tableau ci-dessous couvre ceux utilisés dans cet exemple ainsi que les paramètres optionnels disponibles dans les versions récentes de Kubernetes :

ParamètreObligatoireDescription
maxSkewOuiDifférence maximale autorisée du nombre de pods entre deux zones quelconques
topologyKeyOuiDoit être topology.kubernetes.io/zone pour les pods basés sur ECI
whenUnsatisfiableOuiDoNotSchedule bloque le placement si la contrainte ne peut pas être respectée ; ScheduleAnywayDéfinition de la contrainte de répartition permet le placement au mieux
labelSelectorOuiSélectionne les pods à compter lors de l'évaluation du déséquilibre
minDomainsNonNombre minimum de zones éligibles à prendre en compte. Bêta depuis Kubernetes 1.25.
matchLabelKeysNonClés de libellé supplémentaires utilisées pour identifier les pods appartenant au même groupe. Bêta depuis Kubernetes 1.27.
nodeAffinityPolicyNonIndique si les règles d'affinité de nœud sont honorées lors du comptage des pods par zone. Bêta depuis Kubernetes 1.26.
nodeTaintsPolicyNonIndique si les taints de nœud sont honorés lors du comptage des pods par zone. Bêta depuis Kubernetes 1.26.

Étape 2 : Vérifier le résultat de la planification

Exécutez la commande suivante pour voir sur quels nœuds les pods ont été planifiés :

kubectl get po -lapp=with-pod-topology-spread \
  -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName \
  --no-headers | grep -v "<none>"

Pour compter les pods par zone :

kubectl get po -lapp=with-pod-topology-spread \
  -o custom-columns=NODE:.spec.nodeName \
  --no-headers | grep -v "<none>" \
  | xargs -I {} kubectl get no {} -o json \
  | jq '.metadata.labels["topology.kubernetes.io/zone"]' \
  | sort | uniq -c

Exemple 2 : Déployer des pods dans une zone spécifique

Cet exemple crée un Deployment avec 3 réplicas qui doivent tous se trouver dans la même zone. Utilisez ce modèle lorsque la faible latence entre les pods est plus importante que la répartition entre les zones.

Étape 1 : Créer le Deployment

Enregistrez le code YAML suivant dans le fichier deployment.yaml et exécutez la commande kubectl apply -f deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: with-affinity
  labels:
    app: with-affinity
spec:
  replicas: 3
  selector:
    matchLabels:
      app: with-affinity
  template:
    metadata:
      labels:
        app: with-affinity
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - with-affinity
            topologyKey: topology.kubernetes.io/zone
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: type
                operator: NotIn
                values:
                - virtual-kubelet
      tolerations:
        - key: "virtual-kubelet.io/provider"
          operator: "Exists"
          effect: "NoSchedule"
      containers:
      - name: with-affinity
        image: registry.k8s.io/pause:2.0

Les trois sections pertinentes pour la planification sont :

Section Fonction
podAffinity (requiredDuringSchedulingIgnoredDuringExecution, topologyKey: topology.kubernetes.io/zone) Exige que tous les pods portant le libellé app: with-affinity se trouvent dans la même zone. kube-scheduler ne placera pas un pod sauf si cela est réalisable. Consultez la section Node affinity.
nodeAffinity (preferredDuringSchedulingIgnoredDuringExecution, type NotIn virtual-kubelet) Privilégie les nœuds ECS ; bascule sur les nœuds virtuels lorsqu'aucun nœud ECS n'est disponible. Consultez la section Node affinity.
tolerations (virtual-kubelet.io/provider: Exists, NoSchedule) Permet à kube-scheduler de placer des pods sur des nœuds virtuels. Consultez la section Taints and tolerations.

Pour épingler les pods à une zone spécifique au lieu de les laisser se colocaliser là où le premier pod est planifié, remplacez le bloc podAffinity par une affinité de nœud requiredDuringSchedulingIgnoredDuringExecution. La configuration suivante planifie les pods exclusivement dans la zone A de Pékin :

requiredDuringSchedulingIgnoredDuringExecution:
  nodeSelectorTerms:
  - matchExpressions:
    - key: topology.kubernetes.io/zone
      operator: In
      values:
      - cn-beijing-a

Étape 2 : Vérifier le résultat de la planification

Exécutez la commande suivante pour voir sur quels nœuds les pods ont été planifiés :

kubectl get po -lapp=with-affinity \
  -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName \
  --no-headers | grep -v "<none>"

Pour compter les pods par zone :

kubectl get po -lapp=with-affinity \
  -o custom-columns=NODE:.spec.nodeName \
  --no-headers | grep -v "<none>" \
  | xargs -I {} kubectl get no {} -o json \
  | jq '.metadata.labels["topology.kubernetes.io/zone"]' \
  | sort | uniq -c

Répartition topologique stricte des pods ECI

Par défaut, kube-scheduler vise une distribution uniforme entre les zones, mais ne bloque pas le placement des pods lorsque la création ECI échoue dans certaines zones. Cela peut violer silencieusement la contrainte maxSkew.

Par exemple, avec maxSkew: 1 et trois zones (A, B, C), kube-scheduler déploie uniformément les pods d'une charge de travail entre toutes les zones. Si la création ECI échoue dans les zones B et C, les pods ne s'exécutent que dans la zone A, ce qui viole la contrainte spécifiée par maxSkew.

image

Activez la répartition topologique stricte des pods ECI pour garantir le respect de la contrainte. Avec le mode strict activé, kube-scheduler assigne d'abord un pod à chaque zone et retient les pods en attente jusqu'à ce que les pods planifiés soient créés. La figure ci-dessous montre l'état initial : un pod assigné à chaque zone, tous les autres étant en attente.

image

Même après la création du pod A1, kube-scheduler ne planifie pas le pod suivant, car si la zone B ou C échouait, la contrainte serait violée. Ce n'est qu'après la création du pod B1 que kube-scheduler planifie un pod dans la zone C. Les pods ombrés en vert indiquent les pods créés.

image

Pour désactiver la répartition stricte et permettre à kube-scheduler de planifier des pods indépendamment de la satisfaction des contraintes, définissez whenUnsatisfiable: ScheduleAnyway. Pour plus de détails sur les paramètres, consultez la section Définition de la contrainte de répartition.