Todos os produtos
Search
Central de documentação

Container Service for Kubernetes:Distribuir pods ECI entre zonas e configurar agendamento por afinidade

Última atualização: Jun 27, 2026

Quando a criação de pods baseados em ECI falha em uma zona, todas as réplicas concentradas nessa zona ficam indisponíveis. Dois padrões de falha são comuns: todas as réplicas são alocadas na mesma zona durante o agendamento, e falhas silenciosas na criação de ECI em algumas zonas violam as garantias de distribuição. Este tópico explica como usar restrições de distribuição de topologia do Kubernetes e regras de afinidade para evitar ambos os problemas em um cluster ACK gerenciado Pro.

Pré-requisitos

Antes de começar, verifique se você possui:

  • Um cluster ACK gerenciado Pro que atenda aos seguintes requisitos:

  • Múltiplas zonas (vSwitches) configuradas no eci-profile para permitir o agendamento de pods entre zonas

  • Os campos nodeAffinity, podAffinity ou topologySpreadConstraints definidos na especificação do pod, ou uma ResourcePolicy configurada para o pod

Nota

Para agendar pods em nós virtuais baseados em ARM, adicione tolerâncias que correspondam aos taints desses nós.

Observações de uso

  • Defina topologyKey como topology.kubernetes.io/zone.

  • O comportamento de agendamento descrito neste tópico não se aplica quando:

    • A anotação k8s.aliyun.com/eci-schedule-strategy: "VSwitchOrdered" está definida no pod (o agendamento multizona segue uma ordem fixa de vSwitch).

    • A anotação k8s.aliyun.com/eci-fail-strategy: "fail-fast" está definida no pod.

Escolha uma abordagem

Dois mecanismos do Kubernetes atendem a objetivos diferentes:

Objetivo

Mecanismo

Quando usar

Distribuir pods uniformemente por todas as zonas disponíveis

topologySpreadConstraints

Alta disponibilidade — as réplicas são distribuídas de modo que a falha de uma única zona afete apenas uma fração delas

Fixar pods em uma zona específica ou mantê-los colocalizados

podAffinity + nodeAffinity

Desempenho — baixa latência entre pods é essencial, ou sua carga de trabalho deve ser executada em uma zona específica

Ambos os exemplos abaixo usam os mesmos campos obrigatórios para ECI: uma tolerância para virtual-kubelet.io/provider e uma afinidade de nó preferredDuringSchedulingIgnoredDuringExecution que prefere nós Elastic Compute Service (ECS) em vez de nós virtuais. A única diferença é a regra de distribuição ou afinidade em si.

Exemplo 1: Distribuir pods uniformemente entre zonas

Este exemplo cria um Deployment com 10 réplicas distribuídas uniformemente por todas as zonas disponíveis.

Etapa 1: Criar o Deployment

Salve o YAML a seguir em deployment.yaml e execute 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"

As três seções relevantes para o agendamento são:

Seção

Função

nodeAffinity (preferredDuringSchedulingIgnoredDuringExecution, type NotIn virtual-kubelet)

Prefere nós ECS; recorre a nós virtuais quando nenhum nó ECS estiver disponível. Consulte Node affinity.

topologySpreadConstraints (maxSkew: 1, topologyKey: topology.kubernetes.io/zone, whenUnsatisfiable: DoNotSchedule)

Mantém a diferença na contagem de pods entre quaisquer duas zonas em no máximo 1. O kube-scheduler bloqueia a alocação se essa restrição não puder ser satisfeita. Consulte topologySpreadConstraints field.

tolerations (virtual-kubelet.io/provider: Exists, NoSchedule)

Permite que o kube-scheduler aloque pods em nós virtuais, que possuem esse taint por padrão. Consulte Taints and tolerations.

Nota

Para agendar pods em nós virtuais baseados em ARM, adicione uma tolerância para o taint específico de ARM.

O campo topologySpreadConstraints aceita vários parâmetros. A tabela abaixo cobre os usados neste exemplo e parâmetros opcionais disponíveis em versões recentes do Kubernetes:

ParâmetroObrigatórioDescrição
maxSkewSimDiferença máxima permitida na contagem de pods entre quaisquer duas zonas
topologyKeySimDeve ser topology.kubernetes.io/zone para pods baseados em ECI
whenUnsatisfiableSimDoNotSchedule bloqueia a alocação se a restrição não puder ser atendida; ScheduleAnywayDefinição de restrição de distribuição permite a alocação com melhor esforço
labelSelectorSimSeleciona os pods a serem contados ao avaliar a assimetria
minDomainsNãoNúmero mínimo de zonas elegíveis a considerar. Beta desde o Kubernetes 1.25.
matchLabelKeysNãoChaves de rótulo adicionais usadas para identificar pods pertencentes ao mesmo grupo. Beta desde o Kubernetes 1.27.
nodeAffinityPolicyNãoDefine se as regras de afinidade de nó são respeitadas ao contar pods por zona. Beta desde o Kubernetes 1.26.
nodeTaintsPolicyNãoDefine se os taints de nó são respeitados ao contar pods por zona. Beta desde o Kubernetes 1.26.

Etapa 2: Verificar o resultado do agendamento

Execute o comando a seguir para ver em quais nós os pods foram alocados:

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

Para contar pods por zona:

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

Exemplo 2: Implantar pods em uma zona específica

Este exemplo cria um Deployment com 3 réplicas que devem ser alocadas na mesma zona. Use este padrão quando a baixa latência entre pods for mais importante do que a distribuição entre zonas.

Etapa 1: Criar o Deployment

Salve o YAML a seguir em deployment.yaml e execute 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

As três seções relevantes para o agendamento são:

Seção

Função

podAffinity (requiredDuringSchedulingIgnoredDuringExecution, topologyKey: topology.kubernetes.io/zone)

Exige que todos os pods com o rótulo app: with-affinity sejam alocados na mesma zona. O kube-scheduler não aloca um pod a menos que isso seja possível. Consulte Node affinity.

nodeAffinity (preferredDuringSchedulingIgnoredDuringExecution, type NotIn virtual-kubelet)

Prefere nós ECS; recorre a nós virtuais quando nenhum nó ECS estiver disponível. Consulte Node affinity.

tolerations (virtual-kubelet.io/provider: Exists, NoSchedule)

Permite que o kube-scheduler aloque pods em nós virtuais. Consulte Taints and tolerations.

Para fixar pods em uma zona específica em vez de permitir que eles sejam colocalizados onde quer que o primeiro pod seja alocado, substitua o bloco podAffinity por uma afinidade de nó requiredDuringSchedulingIgnoredDuringExecution. A configuração a seguir agenda pods exclusivamente na Zona A de Pequim:

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

Etapa 2: Verificar o resultado do agendamento

Execute o comando a seguir para ver em quais nós os pods foram alocados:

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

Para contar pods por zona:

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

Distribuição estrita de topologia de pods ECI

Por padrão, o kube-scheduler visa uma distribuição uniforme entre zonas, mas não bloqueia a alocação de pods quando a criação de ECI falha em algumas zonas. Isso pode violar silenciosamente a restrição maxSkew.

Por exemplo, com maxSkew: 1 e três zonas (A, B, C), o kube-scheduler distribui uniformemente os pods de uma carga de trabalho entre todas as zonas. Se a criação de ECI falhar na Zona B e na Zona C, os pods serão executados apenas na Zona A — violando a restrição especificada por maxSkew.

image

Ative a distribuição estrita de topologia de pods ECI para garantir que a restrição seja respeitada. Com o modo estrito ativado, o kube-scheduler primeiro despacha um pod para cada zona e retém os pods pendentes até que os pods agendados sejam criados. A figura abaixo mostra o estado inicial: um pod despachado para cada zona, todos os outros pendentes.

image

Mesmo após a criação do Pod A1, o kube-scheduler não agenda o próximo pod — pois, se a Zona B ou a Zona C falhar, a restrição seria violada. Somente após a criação do Pod B1 é que o kube-scheduler agenda um pod para a Zona C. Pods com sombreamento verde indicam pods criados.

image

Para desativar a distribuição estrita e permitir que o kube-scheduler agende pods independentemente da satisfação da restrição, defina whenUnsatisfiable: ScheduleAnyway. Para detalhes sobre os parâmetros, consulte Definição de restrição de distribuição.