Neste tutorial, mostramos como otimizar os recursos disponíveis programando jobs no Google Kubernetes Engine (GKE) com o Kueue. Neste tutorial, você vai aprender a usar o Kueue para gerenciar e programar jobs em lote de maneira eficaz, melhorar a utilização de recursos e simplificar o gerenciamento de cargas de trabalho. Você configura um cluster compartilhado para duas equipes de locatários, em que cada uma tem o próprio namespace e cria jobs que compartilham recursos globais. Você também configura o Kueue para programar os jobs com base nas cotas de recursos definidas.
Este tutorial é destinado a arquitetos de nuvem e engenheiros de plataforma interessados em implementar um sistema em lote usando o GKE. Para saber mais sobre papéis comuns e exemplos de tarefas referenciados no conteúdo do Google Cloud, consulte Funções e tarefas comuns do usuário do GKE.
Antes de ler esta página, confira se você conhece os seguintes conceitos:
Contexto
Os jobs são aplicativos executados até a conclusão, como machine learning, renderização, simulação, análise, CI/CD e cargas de trabalho semelhantes.
O Kueue é um programador de jobs nativos da nuvem que funciona com o programador padrão do Kubernetes, o controlador de jobs e o escalonador automático de clusters para fornecer um sistema de lotes de ponta a ponta. O Kueue implementa o enfileiramento de jobs para decidir quando os jobs devem esperar e quando devem começar, com base em cotas e em uma hierarquia para compartilhar recursos entre as equipes.
O Kueue tem as seguintes características:
- Ele é otimizado para arquiteturas de nuvem, em que os recursos são heterogêneos, intercambiáveis e escalonáveis.
- Ele oferece um conjunto de APIs para gerenciar cotas e gerenciar jobs na fila.
- Ele não reimplementa as funcionalidades atuais, como escalonamento automático, programação de pods ou gerenciamento do ciclo de vida do job.
- O Kueue tem suporte integrado para a API
batch/v1.Job
do Kubernetes. - Pode ser integrado a outras APIs de job.
O Kueue se refere a jobs definidos com qualquer API como cargas de trabalho, para evitar confusão com a API do Job do Kubernetes específica.
Criar o ResourceFlavor
Um ResourceFlavor é um objeto que representa as variações nos nós disponíveis no seu cluster, associando-os a rótulos e taints de nó. Por exemplo, é possível usar o ResourceFlavors para representar VMs com diferentes garantias de provisionamento (por exemplo, spot vs. sob demanda), arquiteturas (por exemplo, CPUs x86 vs. ARM), marcas e modelos (por exemplo, GPUs Nvidia A100 vs. T4).
Neste tutorial, o cluster kueue-autopilot
tem recursos homogêneos.
Como resultado, crie um único ResourceFlavor para o CPU, memória, armazenamento temporário
e GPUs, sem identificadores ou taints.
kubectl apply -f flavors.yaml
Criar o ClusterQueue
Um ClusterQueue é um objeto com escopo de cluster que gerencia um pool de recursos, como CPU, memória e GPU. Ele gerencia os ResourceFlavors e limita o uso e determina a ordem em que as cargas de trabalho são admitidas.
Implante o ClusterQueue:
kubectl apply -f cluster-queue.yaml
A ordem de consumo é determinada por .spec.queueingStrategy
, que apresenta duas configurações:
BestEffortFIFO
- A configuração padrão da estratégia de enfileiramento.
- A entrada da carga de trabalho segue a regra "primeiro a entrar, primeiro a sair" (PEPS). No entanto, se não houver cota suficiente para admitir a carga de trabalho no cabeçalho da fila, a próxima na linha será testada.
StrictFIFO
- Garante a semântico método PEPS.
- A carga de trabalho no cabeçalho da fila pode bloquear a fila até que ela possa ser aceita.
Em cluster-queue.yaml
, você cria um novo ClusterQueue chamado cluster-queue
. Esse
ClusterQueue gerencia quatro recursos, cpu
, memory
, nvidia.com/gpu
e
ephemeral-storage
, com a variação criada em flavors.yaml
.
A cota é consumida pelas solicitações nas especificações do pod da carga de trabalho.
Cada variação inclui limites de uso representados como
.spec.resourceGroups[].flavors[].resources[].nominalQuota
. Nesse caso, o ClusterQueue aceitará
cargas de trabalho se:
- A soma das solicitações da CPU for menor ou igual a 10
- A soma das solicitações de memória for menor ou igual a 10 Gi
- A soma das solicitações da GPU for menor ou igual a 10
- A soma do armazenamento usado for menor ou igual a 10 Gi
Criar o LocalQueue
Um LocalQueue é um objeto com namespace que aceita cargas de trabalho de usuários no namespace.
LocalQueues de diferentes namespaces podem apontar para o mesmo ClusterQueue em que podem compartilhar a cota dos recursos. Nesse caso,
o LocalQueue do namespace team-a
e team-b
aponta para o mesmo ClusterQueue
cluster-queue
em .spec.clusterQueue
.
Cada equipe envia as cargas de trabalho para o LocalQueue no próprio namespace. Em seguida, são alocados recursos pelo ClusterQueue.
Implantar os LocalQueues:
kubectl apply -f local-queue.yaml
Criar Jobs e observar as cargas de trabalho admitidas
Nesta seção, você cria jobs do Kubernetes no namespace team-a
. Um controlador de job no Kubernetes cria um ou mais pods e garante que eles executem uma tarefa específica com sucesso.
O job no namespace team-a
tem os seguintes atributos:
- Ele aponta para a
lq-team-a
LocalQueue. - Ele solicita recursos de GPU definindo o campo
nodeSelector
comonvidia-tesla-t4
. - Ele é composto por três pods que ficam suspensos por 10 segundos em paralelo. Os jobs são
limpos após 60 segundos de acordo com o valor definido no campo
ttlSecondsAfterFinished
. - Ele requer 1.500 miliCPU, 1.536 Mi de memória, 1.536 Mi de armazenamento temporário e três GPUs, já que há três pods.
Os jobs também são criados no arquivo
job-team-b.yaml
,
em que o namespace pertence a team-b
, com solicitações para
representar equipes com necessidades distintas.
Para saber mais, consulte Como implantar cargas de trabalho da GPU no Autopilot.
Em um novo terminal, observe o status do ClusterQueue que é atualizado a cada dois segundos:
watch -n 2 kubectl get clusterqueue cluster-queue -o wide
Em um novo terminal, observe o status dos nós:
watch -n 2 kubectl get nodes -o wide
Em um novo terminal, crie jobs para a fila local a partir do namespace
team-a
eteam-b
a cada 10 segundos:./create_jobs.sh job-team-a.yaml job-team-b.yaml 10
Observe os jobs sendo enfileirados, aceitos no ClusterQueue e os nós sendo criados com o Autopilot do GKE.
Consiga um job do namespace
team-a
:kubectl -n team-a get jobs
O resultado será assim:
NAME COMPLETIONS DURATION AGE sample-job-team-b-t6jnr 3/3 21s 3m27s sample-job-team-a-tm7kc 0/3 2m27s sample-job-team-a-vjtnw 3/3 30s 3m50s sample-job-team-b-vn6rp 0/3 40s sample-job-team-a-z86h2 0/3 2m15s sample-job-team-b-zfwj8 0/3 28s sample-job-team-a-zjkbj 0/3 4s sample-job-team-a-zzvjg 3/3 83s 4m50s
Copie o nome de um job da etapa anterior e observe o status e os eventos de admissão de um job usando a API do Workloads:
kubectl -n team-a describe workload JOB_NAME
Quando os jobs pendentes começam a aumentar a partir do ClusterQueue, encerre o script ao pressionar
CTRL + C
no script em execução.Quando todos os jobs forem concluídos, observe que os nós estão sendo reduzidos.