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:
Versão 1.22 ou superior do Kubernetes
Componente ACK Virtual Node versão 2.10.0 ou superior
Componente kube-scheduler versão 5,9 ou superior, com a política de agendamento de pods baseada em nó virtual ativada
Múltiplas zonas (vSwitches) configuradas no eci-profile para permitir o agendamento de pods entre zonas
Os campos
nodeAffinity,podAffinityoutopologySpreadConstraintsdefinidos na especificação do pod, ou uma ResourcePolicy configurada para o pod
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
topologyKeycomotopology.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 |
|
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 |
|
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 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 |
|
|
Exige que todos os pods com o rótulo |
|
|
Prefere nós ECS; recorre a nós virtuais quando nenhum nó ECS estiver disponível. Consulte Node affinity. |
|
|
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.
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.
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.
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.