Cluster de GPU compartilhado no HyperPod: três desenhos e quando cada um vale
A pergunta que costuma abrir a discussão de cluster de GPU compartilhado é "como divido as máquinas entre os times?". A pergunta que decide se o desenho sobrevive é outra: quando o job de treino do time de pesquisa for despejado às 2h da manhã para abrir espaço para um endpoint de inferência, quem fica sabendo, quantas horas de GPU foram jogadas fora e em qual centro de custo isso cai? A arquitetura de referência que a AWS publicou em 08/10/2026 para o SageMaker HyperPod com EKS responde boa parte disso. Neste texto eu a coloco lado a lado com as duas alternativas que vejo com mais frequência e digo em que condições cada uma vale o custo de manter.
A escolha real: três formas de dividir GPU
Opção A, um cluster HyperPod EKS compartilhado com Task Governance: o desenho do post. Cada time tem um namespace hyperpod-ns-<time>, um domínio SageMaker próprio para quem entra pelo Studio e um permission set no IAM Identity Center para quem entra pelo CLI. A justiça entre times fica com o Task Governance, construído sobre Kueue: cota garantida por time, empréstimo de capacidade ociosa e classes de prioridade.
Opção B, um cluster por time, de preferência em contas separadas: a fronteira é a conta AWS. Não existe vizinho barulhento porque não existe vizinho. Em compensação, cada time carrega o próprio piso de capacidade, e GPU parada num cluster não socorre fila cheia no outro.
Opção C, cluster compartilhado só com namespaces e ResourceQuota: é o que aparece quando a plataforma nasce de um cluster de um time só e outros vão chegando. Funciona até a primeira semana de contenção, quando a cota vira teto rígido e a ordem de chegada decide quem treina.
A diferença entre as três não está no custo de subir o cluster. Está no que cada uma exige de operação contínua: revisar cota, depurar admissão no Kueue, manter o webhook de UID/GID, reconciliar chargeback. Esse é o custo que fica por anos, e é ele que eu uso para comparar.
Do login à GPU: onde cada fronteira do desenho A é aplicada
Identidade decide o namespace, o namespace decide a fila, a fila decide se o pod entra com cota própria ou emprestada, e o namespace vira a chave do chargeback.
- Permission set · AWSReservedSSO_TeamA_*
- SageMaker domain · TeamA-domain + TeamA-role
- EKS access entries · escopo: hyperpod-ns-team-a
- Admission webhook · UID/GID via sessionName
- DynamoDB · mapa POSIX
- LocalQueue · hyperpod-ns-team-a-localqueue
- ClusterQueue · cota garantida + borrow limit
- Idle resource sharing · IdleResourceSharing: Enabled
- Nós HyperPod · health checks + auto-recovery
- FSx for Lustre · /fsx/TeamA
- Kubecost · custo por namespace
Isolamento: namespace é fronteira de organização, não de segurança
O próprio post diz isso com todas as letras: namespace é uma fronteira de isolamento, não uma fronteira rígida de segurança, e o desenho mira vários times da mesma empresa, não inquilinos que não confiam entre si. Concordo, e acrescento o que isso significa em ambiente regulado.
O desenho A empilha quatro controles: access entries do EKS escopadas por namespace (uma para o role do domínio, outra para o role AWSReservedSSO_<permission-set>_<id>), RBAC que devolve Forbidden em chamada cruzada, NetworkPolicy default-deny por namespace e S3 restrito ao prefixo do time. Os quatro rodam sobre o mesmo kernel, os mesmos drivers NVIDIA e o mesmo control plane.
Falha silenciosa número um: NetworkPolicy sem um CNI que a aplique é só YAML. Se o Amazon VPC CNI não estiver com network policy habilitada, o kubectl apply passa, o objeto existe e nenhum pacote é bloqueado. Teste com um pod do time B tentando abrir conexão para um serviço do time A antes de chamar a fronteira de pronta.
A minha régua é a seguinte. Se os times compartilham o mesmo regime regulatório e a mesma classificação de dado, namespace basta. Se um time treina com dado de cliente sob LGPD e outro com dado sintético, ou se um auditor de BACEN 4.893 vai pedir segregação demonstrável, a fronteira certa é conta, e o desenho volta para B.
Justiça: cota, empréstimo e quem é despejado
O Task Governance separa duas políticas. Compute prioritization decide como a capacidade ociosa é distribuída (first-come first-serve ou fair-share) e como tarefas entram na fila (ordem de chegada ou task ranking com classes de prioridade). Compute allocation define, por time, a cota garantida, o peso de fair-share de 0 a 100 e a postura de empréstimo: Lend and Borrow, Lend ou Don't Lend. O limite de empréstimo pode ser percentual, até 10.000% da cota, ou absoluto por tipo de instância.
O exemplo da documentação mostra a mecânica: time A com cota 6 usando 2, time B com cota 5 usando 4, chega um job de 4 no time B e 3 unidades saem emprestadas do A. O que a documentação também diz, e que define a operação, é que tarefa rodando com cota emprestada pode ser preemptada por tarefa de prioridade maior quando acaba a capacidade.
Falha silenciosa número dois: job sem kueue.x-k8s.io/priority-class recebe a prioridade mais baixa. Um endpoint de inferência publicado sem o label vira o primeiro candidato a despejo do cluster.
Preempção tem preço em GPU-hora. Um treino de 16 GPUs emprestadas com checkpoint a cada 30 minutos perde até 8 GPU-horas por despejo, 4 em média. Se o cluster despeja esse job duas vezes por dia, são cerca de 240 GPU-horas por mês jogadas fora sem aparecer em alerta nenhum. Por isso eu trato capacidade emprestada como spot: só entra nela job com checkpoint em FSx e retomada idempotente.
Chargeback: quem paga a GPU ociosa e a emprestada
O post usa Kubecost agrupando custo por namespace, e como namespace já é o time, não precisa de tag extra no workload. Funciona para a pergunta "quanto o time A consumiu". Não responde sozinho duas perguntas que aparecem no primeiro fechamento de mês.
A GPU emprestada: quando o time B roda em cota do time A, o pod está no namespace do B. Cobrar do B é o certo, mas o time A vai olhar o relatório e ver que pagou por uma cota garantida que outro usou. Decida antes se o preço da cota garantida é fixo (o time A paga a reserva, use ou não) ou se é por uso. As duas regras são defensáveis; mudar de regra no meio do trimestre não é.
A GPU ociosa: capacidade não alocada a nenhuma cota precisa de dono no relatório. O Split Cost Allocation Data para EKS, que passou a cobrir GPU, Trainium e Inferentia em 02/09/2025, separa custo por pod e reporta capacidade não usada à parte, com peso GPU contra CPU e memória de 9:1 no exemplo da documentação. Esse exemplo é de instância EC2. Os nós do HyperPod são instâncias ml.* cobradas pelo SageMaker, então confirme na sua fatura se esses dados aparecem antes de trocar o Kubecost por CUR. Eu manteria o Kubecost como fonte de chargeback e usaria o CUR para conciliar o total.
Os três desenhos lado a lado
| Critério | A: HyperPod compartilhado + Task Governance | B: um cluster por time | C: namespaces + ResourceQuota |
|---|---|---|---|
| Fronteira de isolamento | Namespace + access entry + NetworkPolicy | Conta AWS | Namespace + RBAC |
| GPU ociosa de um time | Emprestada, com limite e preempção | Parada | Parada (cota é teto rígido) |
| Contenção | Fair-share por peso 0–100 + task ranking | Não existe entre times | Ordem de chegada |
| Chargeback | Por namespace, exige regra para empréstimo | Fatura da conta, trivial | Por namespace |
| Peças a manter | Políticas de cota, webhook UID/GID, Kubecost, dashboards | N clusters, N upgrades, N pipelines | Poucas, até a primeira disputa |
| Quando falha mal | Job sem priority-class ou sem checkpoint | Utilização baixa vira custo fixo | Time grande monopoliza o cluster |
Matriz de decisão
A: HyperPod compartilhado + Task Governance
- GPU ociosa de um time vira capacidade do outro, com
IdleResourceSharingcobrindo até o que não tem cota - Prioridade explícita: inferência de produção preempta experimento
- Um upgrade de driver e de EKS para todos os times
- Namespace não segura auditoria de segregação forte
- Webhook de UID/GID e mapa no DynamoDB viram peças suas
- Preempção desperdiça GPU-hora se o job não faz checkpoint
Padrão para times da mesma empresa sob o mesmo regime
B: um cluster por time
- Segregação demonstrável por conta, IAM e fatura
- Blast radius de um upgrade ruim fica em um time
- Cada time paga o próprio piso de GPU, mesmo parado
- Plataforma multiplicada por N
Quando dado ou regulação diferem entre times
C: namespaces + ResourceQuota
- Nada novo para aprender
- Sem empréstimo, sem prioridade entre times, sem fair-share
- A disputa por GPU vira reunião, não política
Só como etapa até o segundo time chegar
Cota garantida não é capacidade garantida
A documentação manda manter a soma das cotas abaixo da capacidade do cluster: 20 instâncias, soma das cotas abaixo de 20. Só que o HyperPod tira nó doente de circulação, e o idle resource sharing já exclui nó NotReady ou unschedulable da conta. A cota dos times não encolhe junto. Num cluster de 16 nós com 2 em recuperação, uma soma de cotas igual a 16 promete capacidade que não existe naquela hora. Eu deixo uma folga de pelo menos um nó por tipo de instância fora de qualquer cota.
Eu começaria pelo desenho A, mas com três regras escritas antes do primeiro job: todo manifesto sem kueue.x-k8s.io/priority-class é rejeitado por política de admissão, todo job que roda em cota emprestada grava checkpoint em FSx em intervalo conhecido, e a regra de cobrança da cota emprestada fica assinada pelos donos dos centros de custo. Também definiria o failurePolicy do webhook de UID/GID como decisão explícita: Fail para o cluster parar de agendar quando o DynamoDB não responde, Ignore só se aceitar pod com identidade POSIX errada escrevendo no /fsx. Já vi plataforma compartilhada morrer não por limite técnico, mas porque o primeiro despejo sem explicação fez um time pedir cluster próprio. A lição: em cluster compartilhado, previsibilidade vale mais que utilização.
Veredito
Use a Opção A (HyperPod compartilhado com Task Governance) quando os times pertencem à mesma empresa, tratam dados da mesma classificação e você tem alguém dono das políticas de cota e da observabilidade do Kueue (kubectl describe workload precisa virar rotina, não arqueologia). Use a Opção B (cluster por conta) quando um time opera sob LGPD com dado de cliente e outro não, ou quando a auditoria exige segregação por conta; aceite pagar a GPU ociosa como preço do isolamento. Trate a Opção C como estado transitório: assim que o segundo time disputar GPU, migre para A. O ganho do desenho A não é ter um cluster só, é poder emprestar GPU parada sem negociar em reunião, e ele só se paga se o despejo for previsível e o chargeback for acordado antes.
Referências
Continue lendo
Deep dives de arquitetura, AWS, IA e mercado: direto no seu email. Grátis.
Sem spam · cancele quando quiser
Pergunte ao Fernando sobre isto
Uma resposta focada sobre este artigo, do meu assistente de IA, baseada no meu trabalho.
Participe da conversa
Entre para comentar
Confirme seu e-mail para participar, você também recebe a newsletter. Sem senha.