Evite deadlocks em jobs distribuídos garantindo que todos os pods necessários iniciem juntos ou que nenhum inicie.
Como funciona
O ACK implementa o gang scheduling por meio de um recurso PodGroup. O ACK associa cada pod a um PodGroup com uma contagem mínima de pods (min-available). O agendador mantém o grupo no estado Pending até atingir o mínimo e, em seguida, despacha todos os pods juntos.
O ACK oferece suporte a três métodos para que defina um PodGroup:
|
Método |
Forma de agrupamento dos pods |
Mais indicado para |
|
Rótulos |
O kube-scheduler cria automaticamente um PodGroup |
Jobs simples, sem necessidade de um objeto PodGroup separado |
|
PodGroup CRD |
Recurso PodGroup explícito com controle de tempo limite |
Jobs que precisam de |
|
Anotações do Koordinator |
Agrupamento baseado em anotações |
Clusters com a pilha de agendamento do Koordinator |
Todos os métodos exigem que os pods e seus respectivos PodGroups estejam no mesmo namespace. Todos os pods de um PodGroup devem compartilhar a mesma prioridade.
Pré-requisitos
Antes de começar, certifique-se de ter:
Um ACK managed Pro cluster com o Kubernetes 1.16 ou posterior. Upgrade the cluster caso necessário.
Para configurações avançadas (GangGroup e política de correspondência): um cluster com o Kubernetes 1.22 ou posterior e versão do kube-scheduler superior a
1.xx.xx-aliyun-4.0.
Certifique-se de que o pool de nós elástico tenha capacidade máxima de recursos suficiente e rótulos de nó compatíveis para o agendamento de pods. Caso contrário, pode ocorrer falha no uso dos nós expandidos pelo pool de nós elástico.
Ative o gang scheduling
Método 1: Rótulos (recomendado)
Adicione dois rótulos a cada pod. O kube-scheduler cria automaticamente um PodGroup nomeado de acordo com o valor de pod-group.scheduling.sigs.k8s.io/name.
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu # PodGroup name (must be a valid DNS subdomain)
pod-group.scheduling.sigs.k8s.io/min-available: "3" # Minimum pods required to start the job
O valor de pod-group.scheduling.sigs.k8s.io/name deve ser um nome de subdomínio DNS válido.
Método 2: PodGroup CRD
Crie um recurso PodGroup e, em seguida, referencie-o em cada pod por meio de um rótulo.
A partir do ACK 1.31, há suporte apenas para scheduling.x-k8s.io/v1alpha1. O scheduling.sigs.k8s.io/v1alpha1 não tem mais suporte.
# PodGroup resource
apiVersion: scheduling.x-k8s.io/v1alpha1
kind: PodGroup
metadata:
name: nginx
spec:
scheduleTimeoutSeconds: 10 # Seconds to wait before rejecting the group if min-available is not met
minMember: 3 # Minimum number of pods required to start the job
---
# Pod label — must match the PodGroup name and namespace
labels:
pod-group.scheduling.sigs.k8s.io/name: nginx
Método 3: Anotações do Koordinator
Adicione anotações a cada pod. Este método não oferece suporte aos parâmetros total-number ou mode da api do Koordinator.
annotations:
gang.scheduling.koordinator.sh/name: "gang-example"
gang.scheduling.koordinator.sh/min-available: "2"
Configurações avançadas
Agrupar vários gangs (GangGroup)
Alguns jobs possuem funções com diferentes requisitos de min-available — por exemplo, jobs do PyTorch com um servidor de parâmetros e workers. Um único PodGroup não expressa mínimos por função, e PodGroups separados não se coordenam entre as funções.
O GangGroup vincula vários PodGroups. O job inicia somente quando cada gang atinge seu próprio min-available. Adicione o seguinte rótulo a cada pod ou PodGroup (use a chave de anotação para o método do Koordinator):
|
Método |
Recurso |
Chave |
|
Rótulos |
Pod |
|
|
PodGroup CRD |
PodGroup |
|
|
Anotações do Koordinator |
Pod |
|
Exemplo de valor (array JSON de entradas <namespace>/<gang-name>):
pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
O GangGroup requer o Kubernetes 1.22 ou posterior com a versão do kube-scheduler superior a 1.xx.xx-aliyun-4.0 .
Configure política de correspondência
Por padrão, um PodGroup conta apenas pods com pré-alocação de recursos concluída (only-waiting). Use match-policy para incluir pods em outros estados no cálculo do mínimo — por exemplo, quando pods de um ciclo anterior ainda estão em execução.
Adicione o rótulo a cada pod (método de rótulos) ou ao recurso PodGroup (método PodGroup CRD). O método de anotações do Koordinator oferece suporte apenas a once-satisfied.
|
Política de correspondência |
Pods contados para o min-available |
Quando usar |
|
|
Pods com pré-alocação de recursos concluída |
Mais restrita. Use para jobs stateless sem reaproveitamento de ciclos anteriores. |
|
|
Pods no estado Running + pods com pré-alocação concluída |
Use para contar pods em execução de um ciclo anterior no mínimo. |
|
|
Pods no estado Succeeded + Running + com pré-alocação concluída |
Use para jobs que toleram reinícios parciais — pods já concluídos continuam na contagem. |
|
|
Pods com pré-alocação de recursos concluída; o PodGroup torna-se inválido após o atendimento |
Use para jobs de execução única. O PodGroup torna-se inválido assim que o agendador despacha o gang. |
Exemplo baseado em rótulos:
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
Exemplo de PodGroup CRD (adicione ao PodGroup, não ao pod):
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
A configuração da política de correspondência requer o Kubernetes 1.22 ou posterior com a versão do kube-scheduler superior a 1.xx.xx-aliyun-4.0 .
Exemplo: job distribuído do TensorFlow
Este exemplo compara um job distribuído do TensorFlow com e sem gang scheduling. O cluster possui 4 GPUs. O job tem 1 pod PS e 4 pods worker, cada um com exigência de 2 GPUs e min-available definido como 5.
Etapa 1: Instale o Arena e prepare o cluster para jobs do TensorFlow.
O Arena é um subprojeto do Kubeflow para o gerenciamento de ciclos de vida de jobs de machine learning — incluindo configuração de ambiente, preparação de dados, desenvolvimento de modelos, treinamento e previsão — por meio de CLI ou sdk.
Etapa 2: envie o job do TensorFlow. Tanto os modelos de PS quanto de worker incluem rótulos de gang scheduling com min-available: "5".
apiVersion: "kubeflow.org/v1"
kind: "TFJob"
metadata:
name: "tf-smoke-gpu"
spec:
tfReplicaSpecs:
PS:
replicas: 1
template:
metadata:
creationTimestamp: null
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu
pod-group.scheduling.sigs.k8s.io/min-available: "5"
spec:
containers:
- args:
- python
- tf_cnn_benchmarks.py
- --batch_size=32
- --model=resnet50
- --variable_update=parameter_server
- --flush_stdout=true
- --num_gpus=1
- --local_parameter_device=cpu
- --device=cpu
- --data_format=NHWC
image: registry.cn-hangzhou.aliyuncs.com/kubeflow-images-public/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3
name: tensorflow
ports:
- containerPort: 2222
name: tfjob-port
resources:
limits:
cpu: '1'
workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
restartPolicy: OnFailure
Worker:
replicas: 4
template:
metadata:
creationTimestamp: null
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu
pod-group.scheduling.sigs.k8s.io/min-available: "5"
spec:
containers:
- args:
- python
- tf_cnn_benchmarks.py
- --batch_size=32
- --model=resnet50
- --variable_update=parameter_server
- --flush_stdout=true
- --num_gpus=1
- --local_parameter_device=cpu
- --device=gpu
- --data_format=NHWC
image: registry.cn-hangzhou.aliyuncs.com/kubeflow-images-public/tf-benchmarks-gpu:v20171202-bdab599-dirty-284af3
name: tensorflow
ports:
- containerPort: 2222
name: tfjob-port
resources:
limits:
nvidia.com/gpu: 2
workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
restartPolicy: OnFailure
Sem o gang scheduling ativado:
Verifique o status dos pods:
kubectl get pods
Com apenas 4 GPUs, 2 workers entram no estado Running e reivindicam todas as GPUs. Os 2 restantes permanecem no estado Pending, bloqueando o job:
NAME READY STATUS RESTARTS AGE
tf-smoke-gpu-ps-0 1/1 Running 0 6m43s
tf-smoke-gpu-worker-0 1/1 Running 0 6m43s
tf-smoke-gpu-worker-1 1/1 Running 0 6m43s
tf-smoke-gpu-worker-2 0/1 Pending 0 6m43s
tf-smoke-gpu-worker-3 0/1 Pending 0 6m43s
Verifique os logs de um worker em execução:
kubectl logs -f tf-smoke-gpu-worker-0
Os workers aguardam parados pelos pods no estado Pending — as GPUs permanecem retidas e não há execução de treinamento:
INFO|2020-05-19T07:02:18|/opt/launcher.py|27| 2020-05-19 07:02:18.199696: I tensorflow/core/distributed_runtime/master.cc:221] CreateSession still waiting for response from worker: /job:worker/replica:0/task:3
INFO|2020-05-19T07:02:28|/opt/launcher.py|27| 2020-05-19 07:02:28.199798: I tensorflow/core/distributed_runtime/master.cc:221] CreateSession still waiting for response from worker: /job:worker/replica:0/task:2
Com o gang scheduling ativado:
Todos os 5 pods permanecem no estado Pending até o cluster dispor de recursos suficientes para atender ao min-available: 5:
NAME READY STATUS RESTARTS AGE
tf-smoke-gpu-ps-0 0/1 Pending 0 43s
tf-smoke-gpu-worker-0 0/1 Pending 0 43s
tf-smoke-gpu-worker-1 0/1 Pending 0 43s
tf-smoke-gpu-worker-2 0/1 Pending 0 43s
tf-smoke-gpu-worker-3 0/1 Pending 0 43s
Após a adição de 4 GPUs ao cluster, o agendador despacha todos os 5 pods simultaneamente:
kubectl get pods
Saída esperada:
NAME READY STATUS RESTARTS AGE
tf-smoke-gpu-ps-0 1/1 Running 0 3m16s
tf-smoke-gpu-worker-0 1/1 Running 0 3m16s
tf-smoke-gpu-worker-1 1/1 Running 0 3m16s
tf-smoke-gpu-worker-2 1/1 Running 0 3m16s
tf-smoke-gpu-worker-3 1/1 Running 0 3m16s
Verifique o log do worker e confirme o início do treinamento:
kubectl logs -f tf-smoke-gpu-worker-0
Saída esperada:
INFO|2020-05-19T07:15:24|/opt/launcher.py|27| Running warm up
INFO|2020-05-19T07:21:04|/opt/launcher.py|27| Done warm up
INFO|2020-05-19T07:21:04|/opt/launcher.py|27| Step Img/sec loss
INFO|2020-05-19T07:21:05|/opt/launcher.py|27| 1 images/sec: 31.6 +/- 0.0 (jitter = 0.0) 8.318
INFO|2020-05-19T07:21:15|/opt/launcher.py|27| 10 images/sec: 31.1 +/- 0.4 (jitter = 0.7) 8.343
INFO|2020-05-19T07:21:25|/opt/launcher.py|27| 20 images/sec: 31.5 +/- 0.3 (jitter = 0.7) 8.142
Solução de problemas
Erro: "rejected by podgroup xxx"
Quando há vários PodGroups, a fila de backoff do kube-scheduler pode rejeitar pods com pré-alocação concluída em um ciclo durante o processamento de PodGroups subsequentes.
Este é um comportamento esperado. Ignore o erro se a resolução ocorrer em até 20 minutos. Se persistir, abra um ticket.
Próximos passos
Work with capacity scheduling — use grupos de cotas elásticas para melhorar a utilização dos recursos do cluster