Computação e escalonamento automático - Amazon EKS

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Computação e escalonamento automático

Otimização de recursos de GPU e gerenciamento de custos

Agende cargas de trabalho com requisitos de GPU usando rótulos conhecidos

Para AI/ML cargas de trabalho sensíveis a diferentes características da GPU (por exemplo, GPU, memória da GPU), recomendamos especificar os requisitos da GPU usando rótulos de agendamento conhecidos suportados pelos tipos de nós usados com o Karpenter e grupos de nós gerenciados. Deixar de defini-los pode resultar no agendamento de pods em instâncias com recursos de GPU inadequados, causando falhas ou degradação do desempenho. Recomendamos usar o NodeSelector ou o Node afinity para especificar em qual nó um pod deve ser executado e definir os recursos de computação (CPU, memória GPUs etc.) na seção de recursos do pod.

Exemplo

Por exemplo, usando o seletor de nó de nome da GPU ao usar o Karpenter:

apiVersion: v1 kind: Pod metadata: name: gpu-pod-example spec: containers: - name: ml-workload image: <image> resources: limits: nvidia.com/gpu: 1 # Request one NVIDIA GPU nodeSelector: karpenter.k8s.aws/instance-gpu-name: "l40s" # Run on nodes with NVIDIA L40S GPUs

Use o Kubernetes Device Plugin para expor GPUs

Para expor GPUs em nós, o driver da GPU NVIDIA deve estar instalado no sistema operacional do nó e no tempo de execução do contêiner configurado para permitir que o programador do Kubernetes atribua pods aos nós com disponibilidade. GPUs O processo de configuração do NVIDIA Kubernetes Device Plugin depende da AMI EKS Accelerated que você está usando:

  • AMI acelerada por Bottlerocket: essa AMI inclui o driver de GPU NVIDIA e o plug-in de dispositivo NVIDIA Kubernetes está pré-instalado e pronto para uso, permitindo o suporte à GPU pronto para uso. Nenhuma configuração adicional é necessária para expor GPUs ao agendador do Kubernetes.

  • AL2023 AMI acelerada: essa AMI inclui o driver de GPU NVIDIA, mas o plug-in de dispositivo NVIDIA Kubernetes não está pré-instalado. Você deve instalar e configurar o plug-in do dispositivo separadamente, normalmente por meio de um DaemonSet. Observe que, se você usar o eksctl para criar seu cluster e especificar um tipo de instância de GPU (por exemplo,g5.xlarge) no seu ClusterConfig, eksctl selecionará automaticamente a AMI acelerada e instalará o plug-in de dispositivo NVIDIA Kubernetes em cada instância no grupo de nós. Para saber mais, consulte Suporte à GPU na documentação do eksctl.

Para verificar se o NVIDIA Device Plugin está ativo e GPUs exposto corretamente, execute:

kubectl describe node | grep nvidia.com/gpu

Esse comando verifica se o nvidia.com/gpu recurso está dentro da capacidade e dos recursos alocáveis do nó. Por exemplo, um nó com uma GPU deve aparecernvidia.com/gpu: 1. Consulte o Guia de agendamento de GPU do Kubernetes para obter mais informações.

Use blocos de capacidade de ML para garantir a capacidade das instâncias P e Trainium

Os blocos de capacidade para ML permitem que você reserve instâncias de GPU muito procuradas, especificamente instâncias P (por exemplo, p6-b200, p5, p5e, p5en, p4d, p4de) e instâncias Trainium (por exemplo, trn1, trn2), para começar quase imediatamente ou em uma data futura para suportar suas cargas de trabalho de aprendizado de máquina (ML) de curta duração. Essas reservas são ideais para garantir a capacidade para tarefas de computação intensiva, como treinamento e ajuste fino de modelos. EC2 O preço do Capacity Blocks consiste em uma taxa de reserva e uma taxa de sistema operacional. Para saber mais sobre preços, consulte EC2 Capacity Blocks for ML.

GPUs Para reservar AI/ML cargas de trabalho no Amazon EKS para garantir a capacidade previsível, recomendamos usar os blocos de capacidade de ML para reservas de capacidade de curto prazo ou sob demanda (ODCRs) para garantia de capacidade de uso geral.

  • ODCRs permitem que você reserve a capacidade da EC2 instância (por exemplo, instâncias de GPU como g5 ou p5) em uma zona de disponibilidade específica por um período, garantindo disponibilidade, mesmo durante alta demanda. ODCRs não tem compromisso de longo prazo, mas você paga a taxa sob demanda pela capacidade reservada, seja ela usada ou ociosa. No EKS, ODCRs são suportados por tipos de nós como Karpenter e grupos de nós gerenciados. Para priorizar ODCRs no Karpenter, configure o NodeClass para usar o campo. capacityReservationSelectorTerms Consulte a documentação do Karpenter NodePools .

  • Os blocos de capacidade são um mecanismo de reserva especializado para instâncias de GPU (por exemplo, p5, p4d) ou Trainium (trn1, trn2), projetado para cargas de trabalho de ML de curto prazo, como treinamento de modelos, ajuste fino ou experimentação. Você reserva capacidade por um período definido (normalmente de 24 horas a 182 dias) a partir de uma data futura, pagando somente pelo tempo reservado. Eles são pré-pagos, exigem planejamento prévio para as necessidades de capacidade e não oferecem suporte ao escalonamento automático, mas são alocados para redes de baixa latência. EC2 UltraClusters Eles cobram apenas pelo período reservado. Para saber mais, consulte Encontre e compre blocos de capacidade ou comece configurando grupos de nós gerenciados com blocos de capacidade usando as instruções em Criar um grupo de nós gerenciados com blocos de capacidade para ML.

Reserve capacidade por meio do AWS Management Console e configure seus nós para usar blocos de capacidade de ML. Planeje reservas com base em cronogramas de carga de trabalho e teste em um cluster de preparação. Consulte a documentação de blocos de capacidade para obter mais informações.

Considere reservas de capacidade sob demanda, Amazon EC2 Spot ou sob demanda (ODCRs) para instâncias G Amazon EC2

Para EC2 instâncias G Amazon, considere as diferentes opções de compra de instâncias sob demanda, instâncias EC2 spot da Amazon e reservas de capacidade sob demanda. ODCRspermitem que você reserve a capacidade da EC2 instância em uma zona de disponibilidade específica por um determinado período, garantindo a disponibilidade mesmo durante alta demanda. Ao contrário do ML Capacity Blocks, que só estão disponíveis para instâncias P e Trainium, ODCRs podem ser usados para uma variedade maior de tipos de instância, incluindo instâncias G, tornando-os adequados para cargas de trabalho que exigem diferentes recursos de GPU, como inferência ou gráficos. Ao usar as Instâncias EC2 Spot da Amazon, ser capaz de diversificar em diferentes tipos, tamanhos e zonas de disponibilidade de instâncias é fundamental para poder permanecer no Spot por mais tempo.

ODCRs não tem compromisso de longo prazo, mas você paga a taxa sob demanda pela capacidade reservada, seja ela usada ou ociosa. ODCRs podem ser criados para uso imediato ou programados para uma data futura, oferecendo flexibilidade no planejamento da capacidade. No Amazon EKS, ODCRs são compatíveis com tipos de nós como Karpenter e grupos de nós gerenciados. Para priorizar ODCRs no Karpenter, configure o NodeClass para usar o campo. capacityReservationSelectorTerms Consulte a documentação do Karpenter NodePools . Para obter mais informações sobre criação ODCRs, incluindo comandos de CLI, consulte Introdução à reserva de capacidade sob demanda.

Considere outros tipos e tamanhos de instâncias aceleradas

Selecionar a instância e o tamanho acelerados apropriados é essencial para otimizar o desempenho e o custo em suas cargas de trabalho de ML no Amazon EKS. Por exemplo, diferentes famílias de instâncias de GPU têm desempenho e recursos diferentes, como memória de GPU. Para ajudar você a escolher a opção mais econômica, analise as instâncias de GPU disponíveis na página Tipos de EC2 instância em Computação acelerada. Avalie vários tipos e tamanhos de instâncias para encontrar a melhor opção para seus requisitos específicos de carga de trabalho. Considere fatores como número GPUs, memória e desempenho da rede. Ao selecionar cuidadosamente o tipo e o tamanho corretos da instância de GPU, você pode obter melhor utilização de recursos e eficiência de custos em seus clusters EKS.

Se você usar uma instância de GPU em um nó EKS, ela terá o nvidia-device-plugin-daemonset pod no kube-system namespace por padrão. Para ter uma ideia rápida de se você está utilizando totalmente a (s) GPU (s) em sua instância, você pode usar nvidia-smi conforme mostrado aqui:

kubectl exec nvidia-device-plugin-daemonset-xxxxx \ -n kube-system -- nvidia-smi \ --query-gpu=index,power.draw,power.limit,temperature.gpu,utilization.gpu,utilization.memory,memory.free,memory.used \ --format=csv -l 5
  • Se utilization.memory estiver próximo de 100%, seus códigos provavelmente estão limitados à memória. Isso significa que a GPU (memória) está totalmente utilizada, mas pode sugerir que uma otimização adicional do desempenho deva ser investigada.

  • Se utilization.gpu estiver próximo de 100%, isso não significa necessariamente que a GPU esteja totalmente utilizada. Uma métrica melhor a ser observada é a proporção de power.draw parapower.limit. Se essa proporção for de 100% ou mais, seus códigos estão utilizando totalmente a capacidade computacional da GPU.

  • A -l 5 bandeira diz para gerar as métricas a cada 5 segundos. No caso de um único tipo de instância de GPU, o sinalizador de consulta de índice não é necessário.

Para saber mais, consulte instâncias de GPU na documentação da AWS.

Otimize a alocação de recursos de GPU com divisão de tempo, MIG e alocação fracionária de GPU

Limites estáticos de recursos no Kubernetes (por exemplo, CPU, memória, contagem de GPU) podem levar ao provisionamento excessivo ou à subutilização, especialmente para cargas de trabalho dinâmicas, como inferência. AI/ML Selecionar a GPU certa é importante. Para cargas de trabalho de baixo volume ou picos, o corte de tempo permite que várias cargas de trabalho compartilhem uma única GPU compartilhando seus recursos de computação, potencialmente melhorando a eficiência e reduzindo o desperdício. O compartilhamento de GPU pode ser obtido por meio de diferentes opções:

  • Aproveite os seletores de nós/afinidade de nós para influenciar o agendamento: garanta que os nós provisionados e os pods estejam programados de acordo com a carga de trabalho apropriada GPUs (por exemplo,) karpenter.k8s.aws/instance-gpu-name: "a100"

  • Time-Slicing: programa cargas de trabalho para compartilhar os recursos computacionais de uma GPU ao longo do tempo, permitindo execução simultânea sem particionamento físico. Isso é ideal para cargas de trabalho com demandas de computação variáveis, mas pode não ter isolamento de memória.

  • GPU de várias instâncias (MIG): A MIG permite que uma única GPU NVIDIA seja particionada em várias instâncias isoladas e é compatível com NVIDIA Ampere (por exemplo, GPU A100), NVIDIA Hopper (por exemplo, GPU H100) e NVIDIA Blackwell (por exemplo, Blackwell). GPUs GPUs Cada instância MIG recebe recursos dedicados de computação e memória, permitindo o compartilhamento de recursos em ambientes multilocatários ou cargas de trabalho que exigem garantias de recursos, o que permite otimizar a utilização dos recursos da GPU, incluindo cenários como atender a vários modelos com tamanhos de lote diferentes por meio de divisão de tempo.

  • Alocação fracionária de GPU: usa agendamento baseado em software para alocar partes da computação ou da memória de uma GPU às cargas de trabalho, oferecendo flexibilidade para cargas de trabalho dinâmicas. O NVIDIA KAI Scheduler, parte da plataforma Run:AI, permite isso ao permitir que os pods solicitem recursos fracionários de GPU.

Para habilitar esses recursos no EKS, você pode implantar o NVIDIA Device Plugin, que expõe GPUs como recursos programáveis e oferece suporte ao corte de tempo e ao MIG. Para saber mais, consulte Time-Slicing GPUs no Kubernetes e Compartilhamento de GPU no Amazon EKS com o time-slicing e as instâncias aceleradas da NVIDIA. EC2

Exemplo

Por exemplo, para habilitar o corte de tempo com o NVIDIA Device Plugin:

apiVersion: v1 kind: ConfigMap metadata: name: nvidia-device-plugin-config namespace: kube-system data: config.yaml: | version: v1 sharing: timeSlicing: resources: - name: nvidia.com/gpu replicas: 4 # Allow 4 pods to share each GPU

Exemplo

Por exemplo, para usar o KAI Scheduler para alocação fracionária de GPU, implante-o junto com o operador de GPU NVIDIA e especifique recursos de GPU fracionários na especificação do pod:

apiVersion: v1 kind: Pod metadata: name: fractional-gpu-pod-example annotations: gpu-fraction: "0.5" # Annotation for 50% GPU labels: runai/queue: "default" # Required queue assignment spec: containers: - name: ml-workload image: nvcr.io/nvidia/pytorch:25.04-py3 resources: limits: nvidia.com/gpu: 1 nodeSelector: nvidia.com/gpu: "true" schedulerName: kai-scheduler

Resiliência de nós e gerenciamento de tarefas de treinamento

Implemente verificações de integridade do Node com recuperação automatizada

Para trabalhos de treinamento distribuídos no Amazon EKS que exigem comunicação frequente entre nós, como treinamento em modelos de várias GPUs em vários nós, problemas de hardware, como falhas na GPU ou no EFA, podem causar interrupções nos trabalhos de treinamento. Essas interrupções podem levar à perda do progresso do treinamento e ao aumento dos custos, especialmente para AI/ML cargas de trabalho de longa duração que dependem de hardware estável.

Para ajudar a aumentar a resiliência contra falhas de hardware, como falhas de GPU em clusters EKS que executam cargas de trabalho de GPU, recomendamos usar o EKS Node Monitoring Agent with Auto Repair ou a Amazon. SageMaker HyperPod Enquanto o EKS Node Monitoring Agent with Auto Repair fornece recursos como monitoramento de integridade de nós e reparo automático usando mecanismos Kubernetes padrão, SageMaker HyperPod oferece resiliência direcionada e recursos adicionais projetados especificamente para treinamento de ML em grande escala, como verificações de integridade profundas e retomada automática de trabalhos.

  • O EKS Node Monitoring Agent com Node Auto Repair monitora continuamente a integridade do nó lendo os registros e aplicando NodeConditions, incluindo condições padrão Ready e condições específicas do hardware acelerado para identificar problemas como falhas na GPU ou na rede. Quando um nó é considerado insalubre, o Node Auto Repair o isola e o substitui por um novo nó. O reagendamento de pods e o reinício dos trabalhos dependem dos mecanismos padrão do Kubernetes e da política de reinicialização do trabalho.

  • O agente de verificação SageMaker HyperPodprofunda de integridade e monitoramento de integridade monitora continuamente o status de integridade das instâncias baseadas em GPU e Trainium. Ele é personalizado para AI/ML cargas de trabalho, usando rótulos (por exemplo, node-health-status) para gerenciar a integridade do nó. Quando um nó é considerado não íntegro, HyperPod aciona a substituição automática do hardware defeituoso, como. GPUs Por padrão, ele detecta falhas relacionadas à rede no EFA por meio de suas verificações básicas de integridade e oferece suporte à retomada automática de trabalhos de treinamento interrompidos, permitindo que os trabalhos continuem a partir do último ponto de verificação, minimizando as interrupções em tarefas de ML em grande escala.

Tanto para o EKS Node Monitoring Agent com Auto Repair quanto para SageMaker HyperPod clusters usando EFA, para monitorar métricas específicas do EFA, como erros de acesso remoto direto à memória (RDMA) e quedas de pacotes, certifique-se de que o driver AWS EFA esteja instalado. Além disso, recomendamos implantar o complemento CloudWatch Observability ou usar ferramentas como o DCGM Exporter com Prometheus e Grafana para monitorar o EFA, a GPU e, para obter, métricas específicas relacionadas aos seus recursos. SageMaker HyperPod

Desative a consolidação do Karpenter para cargas de trabalho sensíveis à interrupção

Para cargas de trabalho sensíveis a interrupções, como processamento, tarefas de AI/ML previsão em grande escala ou treinamento, recomendamos ajustar as políticas de consolidação do Karpenter para evitar interrupções durante a execução do trabalho. O recurso de consolidação do Karpenter otimiza automaticamente os custos do cluster ao encerrar nós subutilizados ou substituí-los por alternativas mais baratas. No entanto, mesmo quando uma carga de trabalho utiliza totalmente uma GPU, o Karpenter pode consolidar nós se identificar um tipo de instância com preço mais baixo e do tamanho certo que atenda aos requisitos do pod, causando interrupções no trabalho.

A política de WhenEmptyOrUnderutilized consolidação pode encerrar os nós prematuramente, levando a tempos de execução mais longos. Por exemplo, interrupções podem atrasar a retomada do trabalho devido ao reagendamento do pod e ao recarregamento de dados, o que pode ser caro para trabalhos de inferência em lote de longa duração. Para mitigar isso, você pode definir o WhenEmpty e consolidationPolicy configurar uma consolidateAfter duração, como 1 hora, para reter os nós durante picos de carga de trabalho. Por exemplo:

disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m

Essa abordagem melhora a latência de inicialização do pod para cargas de trabalho de inferência em lote com picos e outros trabalhos sensíveis à interrupção, como processamento de dados de inferência on-line em tempo real ou treinamento de modelos, em que o custo da interrupção supera a economia de custos de computação. O Karpenter NodePool Disruption Budgets é outro recurso para gerenciar interrupções no Karpenter. Com os orçamentos, você pode garantir que não mais do que um certo número de nós seja interrompido no NodePool momento escolhido. Você também pode usar orçamentos de interrupção para evitar que todos os nós sejam interrompidos em um determinado horário (por exemplo, horários de pico). Para saber mais, consulte a documentação do Karpenter Consolidation.

Use ttlSecondsAfter Finished para limpar automaticamente os trabalhos do Kubernetes

Recomendamos a configuração de ttlSecondsAfterFinished trabalhos do Kubernetes no Amazon EKS para excluir automaticamente os objetos de trabalho concluídos. Objetos de trabalho persistentes consomem recursos do cluster, como memória do servidor de API, e complicam o monitoramento ao desordenar painéis (por exemplo, Grafana, Amazon). CloudWatch Por exemplo, definir um TTL de 1 hora garante que os trabalhos sejam removidos logo após a conclusão, mantendo seu cluster organizado. Para obter mais detalhes, consulte Limpeza automática de trabalhos concluídos.

Configure a preempção de trabalhos de baixa prioridade para trabalhos e cargas de trabalho de maior prioridade

Para cargas de AI/ML trabalho de prioridade mista no Amazon EKS, você pode configurar a preempção de tarefas de baixa prioridade para garantir que tarefas de maior prioridade (por exemplo, inferência em tempo real) recebam recursos imediatamente. Sem preempção, cargas de trabalho de baixa prioridade, como processos em lote (por exemplo, inferência em lote, processamento de dados), serviços que não sejam em lote (por exemplo, tarefas em segundo plano, tarefas cron) ou tarefas com uso intensivo de CPU/memória (por exemplo, serviços web) podem atrasar pods críticos ocupando nós. A preempção permite que o Kubernetes expulse pods de baixa prioridade quando pods de alta prioridade precisam de recursos, garantindo a alocação eficiente de recursos em nós com, ou memória. GPUs CPUs Recomendamos usar o Kubernetes PriorityClass para atribuir prioridades e controlar o comportamento de PodDisruptionBudget despejo.

apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: low-priority value: 100 --- spec: priorityClassName: low-priority

Consulte a documentação de prioridade e preempção do Kubernetes para obter mais informações.

Escalabilidade e desempenho de aplicativos

Personalize a capacidade de computação para cargas de trabalho de ML com Karpenter ou Static Nodes

Para garantir uma capacidade computacional econômica e responsiva para fluxos de trabalho de aprendizado de máquina (ML) no Amazon EKS, recomendamos adaptar sua estratégia de provisionamento de nós às características da sua carga de trabalho e aos compromissos de custo. Abaixo estão duas abordagens a serem consideradas: just-in-time escalabilidade com Karpenter e grupos de nós estáticos para capacidade reservada.

  • Just-in-time escaladores de plano de dados como o Karpenter: para fluxos de trabalho dinâmicos de ML com demandas de computação variáveis (por exemplo, inferência baseada em GPU seguida por plotagem baseada em CPU), recomendamos usar escaladores de plano de dados como o Karpenter. just-in-time

  • Use grupos de nós estáticos para cargas de trabalho previsíveis: Para cargas de trabalho de ML previsíveis e estáveis ou ao usar instâncias reservadas, os grupos de nós gerenciados pelo EKS podem ajudar a garantir que a capacidade reservada seja totalmente provisionada e utilizada, maximizando a economia. Essa abordagem é ideal para tipos de instância específicos comprometidos por meio de RIs ou ODCRs.

Exemplo

Este é um exemplo de um Karpenter diversificado NodePoolque permite o lançamento de instâncias da g Amazon em que a geração de EC2 instâncias é maior que três.

apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: gpu-inference spec: template: spec: nodeClassRef: group: karpenter.k8s.aws kind: EC2NodeClass name: default requirements: - key: karpenter.sh/capacity-type operator: In values: ["on-demand"] - key: karpenter.k8s.aws/instance-category operator: In values: ["g"] - key: karpenter.k8s.aws/instance-generation operator: Gt values: ["3"] - key: kubernetes.io/arch operator: In values: ["amd64"] taints: - key: nvidia.com/gpu effect: NoSchedule limits: cpu: "1000" memory: "4000Gi" nvidia.com/gpu: "10" *# Limit the total number of GPUs to 10 for the NodePool* disruption: consolidationPolicy: WhenEmpty consolidateAfter: 60m expireAfter: 720h

Exemplo

Exemplo de uso de grupos de nós estáticos para uma carga de trabalho de treinamento:

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ml-cluster region: us-west-2 managedNodeGroups: - name: gpu-node-group instanceType: p4d.24xlarge minSize: 2 maxSize: 2 desiredCapacity: 2 taints: - key: nvidia.com/gpu effect: NoSchedule

Use imperfeições e tolerâncias para evitar que cargas de trabalho não aceleradas sejam programadas em instâncias aceleradas

O agendamento de cargas de trabalho não aceleradas em recursos de GPU não é eficiente em termos de computação. Recomendamos o uso de manchas e tolerância para garantir que os pods de cargas de trabalho não aceleradas não sejam programados em nós inadequados. Consulte a documentação do Kubernetes para obter mais informações.

Escala com base no desempenho do modelo

Para cargas de trabalho de inferência, recomendamos usar o escalonamento automático orientado a eventos (KEDA) do Kubernetes para escalar com base nas métricas de desempenho do modelo, como solicitações de inferência ou taxa de transferência de tokens, com períodos de espera apropriados. Políticas de escalabilidade estática podem provisionar recursos em excesso ou insuficiente, afetando o custo e a latência. Saiba mais na documentação do KEDA.

Alocação dinâmica de recursos para gerenciamento avançado de GPU

A alocação dinâmica de recursos (DRA) representa um avanço fundamental no gerenciamento de recursos da GPU Kubernetes. O DRA vai além das limitações tradicionais de plug-ins de dispositivos para permitir compartilhamento sofisticado de GPU, reconhecimento de topologia e coordenação de recursos entre nós. Disponível na versão 1.33 do Amazon EKS, o DRA aborda desafios críticos em AI/ML cargas de trabalho fornecendo o seguinte:

  • Alocação refinada de GPU

  • Mecanismos avançados de compartilhamento, como serviço multiprocesso (MPS) e GPU de múltiplas instâncias (MIG)

  • Support para arquiteturas de hardware de próxima geração, incluindo NVIDIA 00 GB2 UltraClusters

A alocação tradicional de GPU é tratada GPUs como recursos inteiros opacos, criando uma subutilização significativa (geralmente de 30 a 40% em clusters de produção). Isso ocorre porque as cargas de trabalho recebem acesso exclusivo à totalidade, GPUs mesmo quando exigem apenas recursos fracionários. O DRA transforma esse modelo introduzindo uma alocação estruturada e declarativa que fornece ao programador do Kubernetes visibilidade completa das características do hardware e dos requisitos de carga de trabalho. Isso permite decisões inteligentes de posicionamento e compartilhamento eficiente de recursos.

Vantagens de usar o DRA em vez do plug-in de dispositivo NVIDIA

O plug-in de dispositivo NVIDIA (a partir da versão0.12.0) oferece suporte a mecanismos de compartilhamento de GPU, incluindo corte de tempo, MPS e MIG. No entanto, existem limitações arquitetônicas que o DRA aborda.

Limitações do plug-in do dispositivo NVIDIA

  • Configuração estática: as configurações de compartilhamento de GPU (réplicas de divisão de tempo e configurações de MPS) exigem pré-configuração em todo o cluster. ConfigMaps Isso dificulta o fornecimento de diferentes estratégias de compartilhamento para diferentes cargas de trabalho.

  • Seleção granular limitada: embora o plug-in do dispositivo exponha as características da GPU por meio de rótulos de nós, as cargas de trabalho não podem solicitar dinamicamente configurações específicas da GPU (tamanho da memória e recursos de computação) como parte da decisão de agendamento.

  • Sem coordenação de recursos entre nós: não é possível gerenciar recursos de GPU distribuídos em vários nós ou expressar requisitos complexos de topologia, como NVLink domínios para sistemas como o NVIDIA 00. GB2

  • Restrições do agendador: o programador do Kubernetes trata os recursos da GPU como números inteiros opacos, limitando sua capacidade de tomar decisões com base na topologia ou lidar com dependências complexas de recursos.

  • Complexidade da configuração: a configuração de diferentes estratégias de compartilhamento requer uma rotulagem cuidadosa ConfigMaps e múltipla de nós, criando complexidade operacional.

Soluções com DRA

  • Seleção dinâmica de recursos: o DRA permite que as cargas de trabalho especifiquem requisitos detalhados (memória da GPU, versões do driver e atributos específicos) no momento da solicitação. resourceclaims Isso permite uma correspondência mais flexível de recursos.

  • Reconhecimento da topologia: por meio de parâmetros estruturados e seletores de dispositivos, o DRA lida com requisitos complexos, como comunicação entre nós de GPU e interconexões coerentes com a memória.

  • Gerenciamento de recursos entre nós: computeDomains permita a coordenação de recursos de GPU distribuídos em vários nós, o que é essencial para sistemas como GB2 00 com canais IMEX.

  • Configuração específica da carga de trabalho: cada uma ResourceClaim especifica diferentes estratégias e configurações de compartilhamento, permitindo um controle refinado por carga de trabalho, em vez de configurações em todo o cluster.

  • Integração aprimorada do agendador: o DRA fornece ao programador informações detalhadas do dispositivo e permite decisões de posicionamento mais inteligentes com base na topologia do hardware e nas características dos recursos.

Importante: O DRA não substitui totalmente o plug-in do dispositivo NVIDIA. O driver NVIDIA DRA funciona junto com o plug-in do dispositivo para fornecer recursos aprimorados. O plug-in do dispositivo continua lidando com a descoberta e o gerenciamento básicos da GPU, enquanto o DRA adiciona recursos avançados de alocação e agendamento.

Instâncias suportadas pelo DRA e seus recursos

O suporte ao DRA varia de acordo com a família de EC2 instâncias da Amazon e a arquitetura da GPU, conforme mostrado na tabela a seguir.

Família de instâncias Tipo de GPU Corte no tempo Suporte MIG Suporte MPS Suporte IMEX Casos de uso

G5

NVIDIA A10G

Sim

Não

Sim

Não

Cargas de trabalho de inferência e gráficos

G6

NVIDIA L4

Sim

Não

Sim

Não

Inferência de IA e processamento de vídeo

G6e

NVIDIA L40S

Sim

Não

Sim

Não

Treinamento, inferência e gráficos

P4D/P4de

NVIDIA A100

Sim

Sim

Sim

Não

Treinamento em grande escala e HPC

P5

NVIDIA H100

Sim

Sim

Sim

Não

Treinamento do modelo básico

P6

NVIDIA B200

Sim

Sim

Sim

Não

Modelos de bilhões ou trilhões de parâmetros, treinamento distribuído e inferência

P6e

NVIDIA 00 GB2

Sim

Sim

Sim

Sim

Modelos de bilhões ou trilhões de parâmetros, treinamento distribuído e inferência

A seguir estão as descrições de cada recurso na tabela:

  • Divisão de tempo: permite que várias cargas de trabalho compartilhem recursos de computação da GPU ao longo do tempo.

  • GPU de várias instâncias (MIG): particionamento em nível de hardware que cria instâncias de GPU isoladas.

  • Serviço multiprocesso (MPS): permite a execução simultânea de vários processos CUDA em uma única GPU.

  • Internode Memory Exchange (IMEX): comunicação coerente com a memória entre os nós para 00. GB2 UltraClusters

Recursos adicionais

Para obter mais informações sobre os drivers Kubernetes DRA e NVIDIA DRA, consulte os seguintes recursos em: GitHub

Configure a alocação dinâmica de recursos para gerenciamento avançado de GPU

O tópico a seguir mostra como configurar a alocação dinâmica de recursos (DRA) para gerenciamento avançado de GPU.

Pré-requisitos

Antes de implementar o DRA no Amazon EKS, certifique-se de que seu ambiente atenda aos seguintes requisitos.

Configuração do cluster
Componentes necessários
  • Versão do plug-in do dispositivo NVIDIA 0.17.1 ou posterior

  • Versão do driver NVIDIA DRA 25.3.0 ou posterior

Etapa 1: Criar cluster com um grupo de nós habilitado para DRA usando eksctl

  1. Crie um arquivo de configuração de cluster chamadodra-eks-cluster.yaml:

    --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-west-2 version: '1.33' managedNodeGroups: - name: gpu-dra-nodes amiFamily: AmazonLinux2023 instanceType: g6.12xlarge desiredCapacity: 2 minSize: 1 maxSize: 3 labels: node-type: "gpu-dra" nvidia.com/gpu.present: "true" taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule
  2. Crie o cluster:

    eksctl create cluster -f dra-eks-cluster.yaml

Etapa 2: implantar o plug-in do dispositivo NVIDIA

Implante o plug-in de dispositivo NVIDIA para permitir a descoberta básica da GPU:

  1. Adicione o repositório Helm do plug-in de dispositivo NVIDIA:

    helm repo add nvidia https://nvidia.github.io/k8s-device-plugin helm repo update
  2. Crie valores personalizados para o plug-in do dispositivo:

    cat <<EOF > nvidia-device-plugin-values.yaml gfd: enabled: true nfd: enabled: true tolerations: - key: [nvidia.com/gpu](http://nvidia.com/gpu) operator: Exists effect: NoSchedule EOF
  3. Instale o plug-in do dispositivo NVIDIA:

    helm install nvidia-device-plugin nvidia/nvidia-device-plugin \ --namespace nvidia-device-plugin \ --create-namespace \ --version v0.17.1 \ --values nvidia-device-plugin-values.yaml

Etapa 3: Implantar o gráfico Helm do driver NVIDIA DRA

  1. Crie um arquivo de dra-driver-values.yaml valores para o driver DRA:

    --- nvidiaDriverRoot: / gpuResourcesEnabledOverride: true resources: gpus: enabled: true computeDomains: enabled: true # Enable for GB200 IMEX support controller: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule kubeletPlugin: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: "nvidia.com/gpu.present" operator: In values: ["true"] tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
  2. Adicione o repositório NVIDIA NGC Helm:

    helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update
  3. Instale o driver NVIDIA DRA:

    helm install nvidia-dra-driver nvidia/nvidia-dra-driver-gpu \ --version="25.3.0-rc.2" \ --namespace nvidia-dra-driver \ --create-namespace \ --values dra-driver-values.yaml

Etapa 4: Verificar a instalação do DRA

  1. Verifique se os recursos da API DRA estão disponíveis:

    kubectl api-resources | grep [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1)

    A seguir está a saída esperada:

    deviceclasses [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) false DeviceClass resourceclaims [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) true ResourceClaim resourceclaimtemplates [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) true ResourceClaimTemplate resourceslices [resource.k8s.io/v1beta1](http://resource.k8s.io/v1beta1) false ResourceSlice
  2. Confira as classes de dispositivos disponíveis:

    kubectl get deviceclasses

    Veja a seguir um exemplo da saída esperada:

    NAME AGE compute-domain-daemon.nvidia.com 4h39m compute-domain-default-channel.nvidia.com 4h39m gpu.nvidia.com 4h39m mig.nvidia.com 4h39m

    Quando uma instância de GPU G6 recém-criada se junta ao seu cluster Amazon EKS com o DRA ativado, as seguintes ações ocorrem:

    • O driver NVIDIA DRA descobre automaticamente a GPU A10G e cria duas nesse nó. resourceslices

    • A gpu.nvidia.com fatia registra o dispositivo físico da GPU A10G com suas especificações (memória, capacidade de computação e muito mais).

    • Como o A10G não oferece suporte ao particionamento MIG, a compute-domain.nvidia.com fatia cria um único domínio computacional representando todo o contexto computacional da GPU.

    • Em seguida, eles resourceslices são publicados no servidor da API Kubernetes, disponibilizando os recursos da GPU para agendamento. resourceclaims

      O programador DRA agora pode alocar de forma inteligente essa GPU para pods que solicitam recursos de GPUresourceclaimtemplates, fornecendo um gerenciamento de recursos mais flexível em comparação com as abordagens tradicionais de plug-ins de dispositivos. Isso acontece automaticamente sem intervenção manual. O nó simplesmente fica disponível para cargas de trabalho da GPU quando o driver DRA conclui o processo de descoberta e registro de recursos.

      Quando você executa o seguinte comando:

      kubectl get resourceslices

      Veja a seguir um exemplo da saída esperada:

      NAME NODE DRIVER POOL AGE ip-100-64-129-47.ec2.internal-compute-domain.nvidia.com-rwsts ip-100-64-129-47.ec2.internal compute-domain.nvidia.com ip-100-64-129-47.ec2.internal 35m ip-100-64-129-47.ec2.internal-gpu.nvidia.com-6kndg ip-100-64-129-47.ec2.internal gpu.nvidia.com ip-100-64-129-47.ec2.internal 35m

Avance para Programe uma carga de trabalho de GPU simples usando a alocação dinâmica de recursos.

Programe uma carga de trabalho de GPU simples usando a alocação dinâmica de recursos

Para programar uma carga de trabalho simples da GPU usando a alocação dinâmica de recursos (DRA), siga as etapas a seguir. Antes de continuar, verifique se você seguiuConfigure a alocação dinâmica de recursos para gerenciamento avançado de GPU.

  1. Crie um arquivo básico ResourceClaimTemplate para alocação de GPU com um arquivo chamado: basic-gpu-claim-template.yaml

    --- apiVersion: v1 kind: Namespace metadata: name: gpu-test1 --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: namespace: gpu-test1 name: single-gpu spec: spec: devices: requests: - name: gpu deviceClassName: gpu.nvidia.com
  2. Aplique o modelo:

    kubectl apply -f basic-gpu-claim-template.yaml
  3. Verifique o status:

    kubectl get resourceclaimtemplates -n gpu-test1

    A seguir está um exemplo de saída:

    NAME AGE single-gpu 9m16s
  4. Crie um pod que use o ResourceClaimTemplate com um arquivo chamadobasic-gpu-pod.yaml:

    --- apiVersion: v1 kind: Pod metadata: namespace: gpu-test1 name: gpu-pod labels: app: pod spec: containers: - name: ctr0 image: ubuntu:22.04 command: ["bash", "-c"] args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"] resources: claims: - name: gpu0 resourceClaims: - name: gpu0 resourceClaimTemplateName: single-gpu nodeSelector: NodeGroupType: gpu-dra nvidia.com/gpu.present: "true" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule"
  5. Aplique e monitore o Pod:

    kubectl apply -f basic-gpu-pod.yaml
  6. Verifique o status do pod:

    kubectl get pod -n gpu-test1

    Veja a seguir um exemplo de saída esperada:

    NAME READY STATUS RESTARTS AGE gpu-pod 1/1 Running 0 13m
  7. Verifique o ResourceClaim status:

    kubectl get resourceclaims -n gpu-test1

    Veja a seguir um exemplo de saída esperada:

    NAME STATE AGE gpu-pod-gpu0-l76cg allocated,reserved 9m6s
  8. Veja os registros do pod para ver as informações da GPU:

    kubectl logs gpu-pod -n gpu-test1

    Veja a seguir um exemplo de saída esperada:

    GPU 0: NVIDIA L4 (UUID: GPU-da7c24d7-c7e3-ed3b-418c-bcecc32af7c5)

Continue Técnicas de otimização de GPU com alocação dinâmica de recursos para obter técnicas mais avançadas de otimização de GPU usando o DRA.

Técnicas de otimização de GPU com alocação dinâmica de recursos

As cargas de trabalho de GPU modernas exigem um gerenciamento sofisticado de recursos para alcançar a utilização ideal e a eficiência de custos. O DRA permite várias técnicas avançadas de otimização que abordam diferentes casos de uso e recursos de hardware:

Essas técnicas podem melhorar significativamente a utilização dos recursos. As organizações relatam que a utilização da GPU aumenta de 30 a 40% com a alocação tradicional para 80 a 90% com estratégias de compartilhamento otimizadas. A escolha da técnica depende das características da carga de trabalho, dos requisitos de isolamento e dos recursos do hardware.

Otimize as cargas de trabalho da GPU com divisão de tempo

O corte de tempo permite que várias cargas de trabalho compartilhem recursos computacionais da GPU, programando-as para serem executadas sequencialmente na mesma GPU física. É ideal para cargas de trabalho de inferência com uso esporádico de GPU.

Execute as etapas a seguir.

  1. Defina um ResourceClaimTemplate para dividir o tempo com um arquivo chamado: timeslicing-claim-template.yaml

    --- apiVersion: v1 kind: Namespace metadata: name: timeslicing-gpu --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: timeslicing-gpu-template namespace: timeslicing-gpu spec: spec: devices: requests: - name: shared-gpu deviceClassName: gpu.nvidia.com config: - requests: ["shared-gpu"] opaque: driver: gpu.nvidia.com parameters: apiVersion: resource.nvidia.com/v1beta1 kind: GpuConfig sharing: strategy: TimeSlicing
  2. Defina um pod usando o corte de tempo com um arquivo chamado: timeslicing-pod.yaml

    --- # Pod 1 - Inference workload apiVersion: v1 kind: Pod metadata: name: inference-pod-1 namespace: timeslicing-gpu labels: app: gpu-inference spec: restartPolicy: Never containers: - name: inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import time import os print(f"=== POD 1 STARTING ===") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Simulate inference workload for i in range(20): x = torch.randn(1000, 1000).cuda() y = torch.mm(x, x.t()) print(f"Pod 1 - Iteration {i+1} completed at {time.strftime('%H:%M:%S')}") time.sleep(60) else: print("No GPU available!") time.sleep(5) resources: claims: - name: shared-gpu-claim resourceClaims: - name: shared-gpu-claim resourceClaimTemplateName: timeslicing-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule --- # Pod 2 - Training workload apiVersion: v1 kind: Pod metadata: name: training-pod-2 namespace: timeslicing-gpu labels: app: gpu-training spec: restartPolicy: Never containers: - name: training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import time import os print(f"=== POD 2 STARTING ===") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Simulate training workload with heavier compute for i in range(15): x = torch.randn(2000, 2000).cuda() y = torch.mm(x, x.t()) loss = torch.sum(y) print(f"Pod 2 - Training step {i+1}, Loss: {loss.item():.2f} at {time.strftime('%H:%M:%S')}") time.sleep(5) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim-2 resourceClaims: - name: shared-gpu-claim-2 resourceClaimTemplateName: timeslicing-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
  3. Aplique o modelo e o Pod:

    kubectl apply -f timeslicing-claim-template.yaml kubectl apply -f timeslicing-pod.yaml
  4. Monitore as reivindicações de recursos:

    kubectl get resourceclaims -n timeslicing-gpu -w

    A seguir está um exemplo de saída:

    NAME STATE AGE inference-pod-1-shared-gpu-claim-9p97x allocated,reserved 21s training-pod-2-shared-gpu-claim-2-qghnb pending 21s inference-pod-1-shared-gpu-claim-9p97x pending 105s training-pod-2-shared-gpu-claim-2-qghnb pending 105s inference-pod-1-shared-gpu-claim-9p97x pending 105s training-pod-2-shared-gpu-claim-2-qghnb allocated,reserved 105s inference-pod-1-shared-gpu-claim-9p97x pending 105s

Primeiro pod (inference-pod-1)

  • Estado: allocated,reserved

  • Significado: o DRA encontrou uma GPU disponível e a reservou para este Pod

  • Status do pod: começa a ser executado imediatamente

Segundo pod (training-pod-2)

  • Estado: pending

  • Significado: Esperando que o DRA configure o corte de tempo na mesma GPU

  • Status do pod: Esperando para ser agendado

  • O estado passará de pending allocated,reserved para running

Otimize as cargas de trabalho da GPU com o MPS

O Multi-Process Service (MPS) permite a execução simultânea de vários contextos CUDA em uma única GPU com melhor isolamento do que o corte de tempo.

Execute as etapas a seguir.

  1. Defina um ResourceClaimTemplate para MPS com um arquivo chamadomps-claim-template.yaml:

    --- apiVersion: v1 kind: Namespace metadata: name: mps-gpu --- apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mps-gpu-template namespace: mps-gpu spec: spec: devices: requests: - name: shared-gpu deviceClassName: gpu.nvidia.com config: - requests: ["shared-gpu"] opaque: driver: gpu.nvidia.com parameters: apiVersion: resource.nvidia.com/v1beta1 kind: GpuConfig sharing: strategy: MPS
  2. Defina um pod usando MPS com um arquivo chamadomps-pod.yaml:

    --- # Single Pod with Multiple Containers sharing GPU via MPS apiVersion: v1 kind: Pod metadata: name: mps-multi-container-pod namespace: mps-gpu labels: app: mps-demo spec: restartPolicy: Never containers: # Container 1 - Inference workload - name: inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import torch.nn as nn import time import os print(f"=== INFERENCE CONTAINER STARTING ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Create inference model model = nn.Sequential( nn.Linear(1000, 500), nn.ReLU(), nn.Linear(500, 100) ).cuda() # Run inference for i in range(1, 999999): with torch.no_grad(): x = torch.randn(128, 1000).cuda() output = model(x) result = torch.sum(output) print(f"Inference Container PID {os.getpid()}: Batch {i}, Result: {result.item():.2f} at {time.strftime('%H:%M:%S')}") time.sleep(2) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim request: shared-gpu # Container 2 - Training workload - name: training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "-c"] args: - | import torch import torch.nn as nn import time import os print(f"=== TRAINING CONTAINER STARTING ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Current GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1024**3:.1f} GB") # Create training model model = nn.Sequential( nn.Linear(2000, 1000), nn.ReLU(), nn.Linear(1000, 500), nn.ReLU(), nn.Linear(500, 10) ).cuda() criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Run training for epoch in range(1, 999999): x = torch.randn(64, 2000).cuda() target = torch.randn(64, 10).cuda() optimizer.zero_grad() output = model(x) loss = criterion(output, target) loss.backward() optimizer.step() print(f"Training Container PID {os.getpid()}: Epoch {epoch}, Loss: {loss.item():.4f} at {time.strftime('%H:%M:%S')}") time.sleep(3) else: print("No GPU available!") time.sleep(60) resources: claims: - name: shared-gpu-claim request: shared-gpu resourceClaims: - name: shared-gpu-claim resourceClaimTemplateName: mps-gpu-template nodeSelector: NodeGroupType: "gpu-dra" nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
  3. Aplique o modelo e crie vários pods MPS:

    kubectl apply -f mps-claim-template.yaml kubectl apply -f mps-pod.yaml
  4. Monitore as reivindicações de recursos:

    kubectl get resourceclaims -n mps-gpu -w

    A seguir está um exemplo de saída:

    NAME STATE AGE mps-multi-container-pod-shared-gpu-claim-2p9kx allocated,reserved 86s

Essa configuração demonstra o verdadeiro compartilhamento de GPU usando o NVIDIA Multi-Process Service (MPS) por meio da alocação dinâmica de recursos (DRA). Ao contrário do corte de tempo, em que as cargas de trabalho se revezam usando a GPU sequencialmente, o MPS permite que os dois contêineres sejam executados simultaneamente na mesma GPU física. O principal insight é que o compartilhamento do DRA MPS requer vários contêineres em um único pod, não vários pods separados. Quando implantado, o driver DRA aloca um ResourceClaim para o pod e configura automaticamente o MPS para permitir que os contêineres de inferência e treinamento sejam executados simultaneamente.

Cada contêiner tem seu próprio espaço de memória de GPU isolado e recursos computacionais, com o daemon MPS coordenando o acesso ao hardware subjacente. Você pode verificar se isso está funcionando fazendo o seguinte:

  • Verificaçãonvidia-smi, que mostrará os dois contêineres como processos M+C (MPS + Compute) que compartilham o mesmo dispositivo de GPU.

  • Monitorando os registros de ambos os contêineres, que exibirão registros de data e hora intercalados, comprovando a execução simultânea.

Essa abordagem maximiza a utilização da GPU, permitindo que cargas de trabalho complementares compartilhem eficientemente o caro hardware da GPU, em vez de deixá-lo subutilizado por um único processo.

Contêiner 1: inference-container
root@mps-multi-container-pod:/workspace# nvidia-smi Wed Jul 16 21:09:30 2025 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.9 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA L4 On | 00000000:35:00.0 Off | 0 | | N/A 48C P0 28W / 72W | 597MiB / 23034MiB | 0% E. Process | | | | N/A | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| | 0 N/A N/A 1 M+C python 246MiB | +-----------------------------------------------------------------------------------------+
Contêiner 2: training-container
root@mps-multi-container-pod:/workspace# nvidia-smi Wed Jul 16 21:16:00 2025 +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.9 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA L4 On | 00000000:35:00.0 Off | 0 | | N/A 51C P0 28W / 72W | 597MiB / 23034MiB | 0% E. Process | | | | N/A | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| | 0 N/A N/A 1 M+C python 314MiB | +-----------------------------------------------------------------------------------------+

Otimize as cargas de trabalho da GPU com a GPU de várias instâncias

A GPU de várias instâncias (MIG) fornece particionamento em nível de hardware, criando instâncias de GPU isoladas com recursos dedicados de computação e memória.

O uso do particionamento MIG dinâmico com vários perfis requer o operador de GPU NVIDIA. O operador de GPU NVIDIA usa o MIG Manager para criar perfis MIG e reinicializar as instâncias da GPU, como P4D, P4De, P5, P6 e outras, para aplicar as alterações de configuração. O GPU Operator inclui recursos abrangentes de gerenciamento de MIG por meio do componente MIG Manager, que observa as alterações nos rótulos dos nós e aplica automaticamente a configuração MIG apropriada. Quando uma alteração do perfil MIG é solicitada, o operador desliga normalmente todos os clientes da GPU, aplica a nova geometria da partição e reinicia os serviços afetados. Esse processo requer uma reinicialização do nó para instâncias de GPU para garantir transições de estado de GPU limpas. É por isso que habilitar WITH–0—REBOOT=true a configuração do MIG Manager é essencial para implantações bem-sucedidas do MIG.

Você precisa do driver NVIDIA DRA e do operador de GPU NVIDIA para trabalhar com o MIG no Amazon EKS. Além disso, você não precisa do NVIDIA Device Plugin e do DCGM Exporter, pois eles fazem parte do NVIDIA GPU Operator. Como o EKS NVIDIA AMIs vem com os drivers NVIDIA pré-instalados, desativamos a implantação de drivers pelo operador da GPU para evitar conflitos e aproveitar os drivers otimizados já presentes nas instâncias. O driver NVIDIA DRA gerencia a alocação dinâmica de recursos para instâncias MIG, enquanto o operador da GPU gerencia todo o ciclo de vida da GPU. Isso inclui configuração MIG, funcionalidade de plug-in de dispositivo, monitoramento por meio de DCGM e descoberta de recursos de nós. Essa abordagem integrada fornece uma solução completa para gerenciamento de GPU corporativa, com isolamento em nível de hardware e recursos dinâmicos de alocação de recursos.

Etapa 1: implantar o operador de GPU NVIDIA
  1. Adicione o repositório NVIDIA GPU Operator:

    helm repo add nvidia https://nvidia.github.io/gpu-operator helm repo update
  2. Crie um gpu-operator-values.yaml arquivo:

    driver: enabled: false mig: strategy: mixed migManager: enabled: true env: - name: WITH_REBOOT value: "true" config: create: true name: custom-mig-parted-configs default: "all-disabled" data: config.yaml: |- version: v1 mig-configs: all-disabled: - devices: all mig-enabled: false # P4D profiles (A100 40GB) p4d-half-balanced: - devices: [0, 1, 2, 3] mig-enabled: true mig-devices: "1g.5gb": 2 "2g.10gb": 1 "3g.20gb": 1 - devices: [4, 5, 6, 7] mig-enabled: false # P4DE profiles (A100 80GB) p4de-half-balanced: - devices: [0, 1, 2, 3] mig-enabled: true mig-devices: "1g.10gb": 2 "2g.20gb": 1 "3g.40gb": 1 - devices: [4, 5, 6, 7] mig-enabled: false devicePlugin: enabled: true config: name: "" create: false default: "" toolkit: enabled: true nfd: enabled: true gfd: enabled: true dcgmExporter: enabled: true serviceMonitor: enabled: true interval: 15s honorLabels: false additionalLabels: release: kube-prometheus-stack nodeStatusExporter: enabled: false operator: defaultRuntime: containerd runtimeClass: nvidia resources: limits: cpu: 500m memory: 350Mi requests: cpu: 200m memory: 100Mi daemonsets: tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" nodeSelector: accelerator: nvidia priorityClassName: system-node-critical
  3. Instale o GPU Operator usando o gpu-operator-values.yaml arquivo:

    helm install gpu-operator nvidia/gpu-operator \ --namespace gpu-operator \ --create-namespace \ --version v25.3.1 \ --values gpu-operator-values.yaml

    Este gráfico do Helm implanta os seguintes componentes e vários perfis MIG:

    • Plugin de dispositivo (agendamento de recursos de GPU)

    • DCGM Exporter (métricas e monitoramento de GPU)

    • Node Feature Discovery (NFD - rotulagem de hardware)

    • Descoberta de recursos de GPU (GFD - rotulagem específica da GPU)

    • MIG Manager (particionamento de GPU de várias instâncias)

    • Kit de ferramentas de contêiner (tempo de execução de contêiner de GPU)

    • Controlador do operador (gerenciamento do ciclo de vida)

  4. Verifique os pods de implantação:

    kubectl get pods -n gpu-operator

    A seguir está um exemplo de saída:

    NAME READY STATUS RESTARTS AGE gpu-feature-discovery-27rdq 1/1 Running 0 3h31m gpu-operator-555774698d-48brn 1/1 Running 0 4h8m nvidia-container-toolkit-daemonset-sxmh9 1/1 Running 1 (3h32m ago) 4h1m nvidia-cuda-validator-qb77g 0/1 Completed 0 3h31m nvidia-dcgm-exporter-cvzd7 1/1 Running 0 3h31m nvidia-device-plugin-daemonset-5ljm5 1/1 Running 0 3h31m nvidia-gpu-operator-node-feature-discovery-gc-67f66fc557-q5wkt 1/1 Running 0 4h8m nvidia-gpu-operator-node-feature-discovery-master-5d8ffddcsl6s6 1/1 Running 0 4h8m nvidia-gpu-operator-node-feature-discovery-worker-6t4w7 1/1 Running 1 (3h32m ago) 4h1m nvidia-gpu-operator-node-feature-discovery-worker-9w7g8 1/1 Running 0 4h8m nvidia-gpu-operator-node-feature-discovery-worker-k5fgs 1/1 Running 0 4h8m nvidia-mig-manager-zvf54 1/1 Running 1 (3h32m ago) 3h35m
  5. Crie um cluster Amazon EKS com um grupo de nós gerenciados pelo P4de para testar os exemplos do MIG:

    apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: dra-eks-cluster region: us-east-1 version: '1.33' managedNodeGroups: # P4DE MIG Node Group with Capacity Block Reservation - name: p4de-mig-nodes amiFamily: AmazonLinux2023 instanceType: p4de.24xlarge # Capacity settings desiredCapacity: 0 minSize: 0 maxSize: 1 # Use specific subnet in us-east-1b for capacity reservation subnets: - us-east-1b # AL2023 NodeConfig for RAID0 local storage only nodeadmConfig: apiVersion: node.eks.aws/v1alpha1 kind: NodeConfig spec: instance: localStorage: strategy: RAID0 # Node labels for MIG configuration labels: nvidia.com/gpu.present: "true" nvidia.com/gpu.product: "A100-SXM4-80GB" nvidia.com/mig.config: "p4de-half-balanced" node-type: "p4de" vpc.amazonaws.com/efa.present: "true" accelerator: "nvidia" # Node taints taints: - key: nvidia.com/gpu value: "true" effect: NoSchedule # EFA support efaEnabled: true # Placement group for high-performance networking placementGroup: groupName: p4de-placement-group strategy: cluster # Capacity Block Reservation (CBR) # Ensure CBR ID matches the subnet AZ with the Nodegroup subnet spot: false capacityReservation: capacityReservationTarget: capacityReservationId: "cr-abcdefghij" # Replace with your capacity reservation ID

    O operador de GPU NVIDIA usa o rótulo adicionado aos nós nvidia.com/mig.config: "p4de-half-balanced" e particiona a GPU com o perfil fornecido.

  6. Faça login na p4de instância.

  7. Execute o seguinte comando:

    nvidia-smi -L

    Você deve ver o seguinte exemplo de saída:

    [root@ip-100-64-173-145 bin]# nvidia-smi -L GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-ab52e33c-be48-38f2-119e-b62b9935925a) MIG 3g.40gb Device 0: (UUID: MIG-da972af8-a20a-5f51-849f-bc0439f7970e) MIG 2g.20gb Device 1: (UUID: MIG-7f9768b7-11a6-5de9-a8aa-e9c424400da4) MIG 1g.10gb Device 2: (UUID: MIG-498adad6-6cf7-53af-9d1a-10cfd1fa53b2) MIG 1g.10gb Device 3: (UUID: MIG-3f55ef65-1991-571a-ac50-0dbf50d80c5a) GPU 1: NVIDIA A100-SXM4-80GB (UUID: GPU-0eabeccc-7498-c282-0ac7-d3c09f6af0c8) MIG 3g.40gb Device 0: (UUID: MIG-80543849-ea3b-595b-b162-847568fe6e0e) MIG 2g.20gb Device 1: (UUID: MIG-3af1958f-fac4-59f1-8477-9f8d08c55029) MIG 1g.10gb Device 2: (UUID: MIG-401088d2-716f-527b-a970-b1fc7a4ac6b2) MIG 1g.10gb Device 3: (UUID: MIG-8c56c75e-5141-501c-8f43-8cf22f422569) GPU 2: NVIDIA A100-SXM4-80GB (UUID: GPU-1c7a1289-243f-7872-a35c-1d2d8af22dd0) MIG 3g.40gb Device 0: (UUID: MIG-e9b44486-09fc-591a-b904-0d378caf2276) MIG 2g.20gb Device 1: (UUID: MIG-ded93941-9f64-56a3-a9b1-a129c6edf6e4) MIG 1g.10gb Device 2: (UUID: MIG-6c317d83-a078-5c25-9fa3-c8308b379aa1) MIG 1g.10gb Device 3: (UUID: MIG-2b070d39-d4e9-5b11-bda6-e903372e3d08) GPU 3: NVIDIA A100-SXM4-80GB (UUID: GPU-9a6250e2-5c59-10b7-2da8-b61d8a937233) MIG 3g.40gb Device 0: (UUID: MIG-20e3cd87-7a57-5f1b-82e7-97b14ab1a5aa) MIG 2g.20gb Device 1: (UUID: MIG-04430354-1575-5b42-95f4-bda6901f1ace) MIG 1g.10gb Device 2: (UUID: MIG-d62ec8b6-e097-5e99-a60c-abf8eb906f91) MIG 1g.10gb Device 3: (UUID: MIG-fce20069-2baa-5dd4-988a-cead08348ada) GPU 4: NVIDIA A100-SXM4-80GB (UUID: GPU-5d09daf0-c2eb-75fd-3919-7ad8fafa5f86) GPU 5: NVIDIA A100-SXM4-80GB (UUID: GPU-99194e04-ab2a-b519-4793-81cb2e8e9179) GPU 6: NVIDIA A100-SXM4-80GB (UUID: GPU-c1a1910f-465a-e16f-5af1-c6aafe499cd6) GPU 7: NVIDIA A100-SXM4-80GB (UUID: GPU-c2cfafbc-fd6e-2679-e955-2a9e09377f78)

O NVIDIA GPU Operator aplicou com sucesso o perfil p4de-half-balanced MIG à sua instância P4DE, criando partições de GPU em nível de hardware conforme configurado. Veja como o particionamento funciona:

O operador da GPU aplicou essa configuração a partir do seu perfil MIG incorporado:

p4de-half-balanced: - devices: [0, 1, 2, 3] # First 4 GPUs: MIG enabled mig-enabled: true mig-devices: "1g.10gb": 2 # 2x small instances (10GB each) "2g.20gb": 1 # 1x medium instance (20GB) "3g.40gb": 1 # 1x large instance (40GB) - devices: [4, 5, 6, 7] # Last 4 GPUs: Full GPUs mig-enabled: false

Com base na sua nvidia-smi -L saída, veja o que o operador da GPU criou:

  • Habilitado para MIG GPUs (0-3): particionado por hardware

    • GPU 0: NVIDIA A100- -80 GB SXM4

      • MIG 3g.40gb Device 0 — Grandes cargas de trabalho (40 GB de memória, 42) SMs

      • MIG 2g.20gb Dispositivo 1 — Cargas de trabalho médias (20 GB de memória, 28) SMs

      • MIG 1g.10gb Dispositivo 2 — Cargas de trabalho pequenas (10 GB de memória, 14) SMs

      • MIG 1g.10gb Dispositivo 3 — Cargas de trabalho pequenas (10 GB de memória, 14) SMs

    • GPU 1: NVIDIA A100- -80 GB SXM4

      • MIG 3g.40gb Dispositivo 0 — Layout de partição idêntico

      • MIG 2g.20gb Dispositivo 1

      • MIG 1g.10gb Dispositivo 2

      • MIG 1g.10gb Dispositivo 3

    • GPU 2 e GPU 3 — Mesmo padrão da GPU 0 e da GPU 1

  • Completo GPUs (4-7): Sem particionamento MIG

    • GPU 4: NVIDIA A100- SXM4 -80 GB — GPU completa de 80 GB

    • GPU 5: NVIDIA A100- SXM4 -80 GB — GPU completa de 80 GB

    • GPU 6: NVIDIA A100- SXM4 -80 GB — GPU completa de 80 GB

    • GPU 7: NVIDIA A100- SXM4 -80 GB — GPU completa de 80 GB

Depois que o operador de GPU NVIDIA cria as partições MIG, o driver NVIDIA DRA detecta automaticamente essas instâncias isoladas de hardware e as disponibiliza para alocação dinâmica de recursos no Kubernetes. O driver DRA descobre cada instância MIG com seu perfil específico (1g.10gb, 2g.20gb, 3g.40gb) e as expõe como recursos programáveis por meio da classe de dispositivo. mig.nvidia.com

O driver DRA monitora continuamente a topologia MIG e mantém um inventário das instâncias disponíveis em todas. GPUs Quando um pod solicita um perfil MIG específico por meio de umResourceClaimTemplate, o driver DRA seleciona de forma inteligente uma instância MIG apropriada de qualquer GPU disponível, permitindo uma verdadeira multilocação em nível de hardware. Essa alocação dinâmica permite que várias cargas de trabalho isoladas sejam executadas simultaneamente na mesma GPU física, mantendo limites rígidos de recursos e garantias de desempenho.

Etapa 2: testar a alocação de recursos do MIG

Agora, vamos executar alguns exemplos para demonstrar como o DRA aloca dinamicamente instâncias MIG para diferentes cargas de trabalho. Implante resourceclaimtemplates e teste os pods para ver como o driver DRA coloca as cargas de trabalho nas partições MIG disponíveis, permitindo que vários contêineres compartilhem recursos de GPU com isolamento em nível de hardware.

  1. Crie mig-claim-template.yaml para conter o MIG: resourceclaimtemplates

    apiVersion: v1 kind: Namespace metadata: name: mig-gpu --- # Template for 3g.40gb MIG instance (Large training) apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mig-large-template namespace: mig-gpu spec: spec: devices: requests: - name: mig-large deviceClassName: mig.nvidia.com selectors: - cel: expression: | device.attributes['gpu.nvidia.com'].profile == '3g.40gb' --- # Template for 2g.20gb MIG instance (Medium training) apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mig-medium-template namespace: mig-gpu spec: spec: devices: requests: - name: mig-medium deviceClassName: mig.nvidia.com selectors: - cel: expression: | device.attributes['gpu.nvidia.com'].profile == '2g.20gb' --- # Template for 1g.10gb MIG instance (Small inference) apiVersion: resource.k8s.io/v1beta1 kind: ResourceClaimTemplate metadata: name: mig-small-template namespace: mig-gpu spec: spec: devices: requests: - name: mig-small deviceClassName: mig.nvidia.com selectors: - cel: expression: | device.attributes['gpu.nvidia.com'].profile == '1g.10gb'
  2. Aplique os três modelos:

    kubectl apply -f mig-claim-template.yaml
  3. Execute o seguinte comando:

    kubectl get resourceclaimtemplates -n mig-gpu

    A seguir está um exemplo de saída:

    NAME AGE mig-large-template 71m mig-medium-template 71m mig-small-template 71m
  4. Crie mig-pod.yaml para agendar vários trabalhos para aproveitar issoresourceclaimtemplates:

    --- # ConfigMap containing Python scripts for MIG pods apiVersion: v1 kind: ConfigMap metadata: name: mig-scripts-configmap namespace: mig-gpu data: large-training-script.py: | import torch import torch.nn as nn import torch.optim as optim import time import os print(f"=== LARGE TRAINING POD (3g.40gb) ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Using GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB") # Large model for 3g.40gb instance model = nn.Sequential( nn.Linear(2048, 1024), nn.ReLU(), nn.Linear(1024, 512), nn.ReLU(), nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10) ).cuda() optimizer = optim.Adam(model.parameters()) criterion = nn.CrossEntropyLoss() print(f"Model parameters: {sum(p.numel() for p in model.parameters())}") # Training loop for epoch in range(100): # Large batch for 3g.40gb x = torch.randn(256, 2048).cuda() y = torch.randint(0, 10, (256,)).cuda() optimizer.zero_grad() output = model(x) loss = criterion(output, y) loss.backward() optimizer.step() if epoch % 10 == 0: print(f"Large Training - Epoch {epoch}, Loss: {loss.item():.4f}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB") time.sleep(3) print("Large training completed on 3g.40gb MIG instance") medium-training-script.py: | import torch import torch.nn as nn import torch.optim as optim import time import os print(f"=== MEDIUM TRAINING POD (2g.20gb) ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Using GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB") # Medium model for 2g.20gb instance model = nn.Sequential( nn.Linear(1024, 512), nn.ReLU(), nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10) ).cuda() optimizer = optim.Adam(model.parameters()) criterion = nn.CrossEntropyLoss() print(f"Model parameters: {sum(p.numel() for p in model.parameters())}") # Training loop for epoch in range(100): # Medium batch for 2g.20gb x = torch.randn(128, 1024).cuda() y = torch.randint(0, 10, (128,)).cuda() optimizer.zero_grad() output = model(x) loss = criterion(output, y) loss.backward() optimizer.step() if epoch % 10 == 0: print(f"Medium Training - Epoch {epoch}, Loss: {loss.item():.4f}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB") time.sleep(4) print("Medium training completed on 2g.20gb MIG instance") small-inference-script.py: | import torch import torch.nn as nn import time import os print(f"=== SMALL INFERENCE POD (1g.10gb) ===") print(f"Process ID: {os.getpid()}") print(f"GPU available: {torch.cuda.is_available()}") print(f"GPU count: {torch.cuda.device_count()}") if torch.cuda.is_available(): device = torch.cuda.current_device() print(f"Using GPU: {torch.cuda.get_device_name(device)}") print(f"GPU Memory: {torch.cuda.get_device_properties(device).total_memory / 1e9:.1f} GB") # Small model for 1g.10gb instance model = nn.Sequential( nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 10) ).cuda() print(f"Model parameters: {sum(p.numel() for p in model.parameters())}") # Inference loop for i in range(200): with torch.no_grad(): # Small batch for 1g.10gb x = torch.randn(32, 512).cuda() output = model(x) prediction = torch.argmax(output, dim=1) if i % 20 == 0: print(f"Small Inference - Batch {i}, Predictions: {prediction[:5].tolist()}, GPU Memory: {torch.cuda.memory_allocated()/1e9:.2f}GB") time.sleep(2) print("Small inference completed on 1g.10gb MIG instance") --- # Pod 1: Large training workload (3g.40gb) apiVersion: v1 kind: Pod metadata: name: mig-large-training-pod namespace: mig-gpu labels: app: mig-large-training workload-type: training spec: restartPolicy: Never containers: - name: large-training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "/scripts/large-training-script.py"] volumeMounts: - name: script-volume mountPath: /scripts readOnly: true resources: claims: - name: mig-large-claim resourceClaims: - name: mig-large-claim resourceClaimTemplateName: mig-large-template nodeSelector: node.kubernetes.io/instance-type: p4de.24xlarge nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule volumes: - name: script-volume configMap: name: mig-scripts-configmap defaultMode: 0755 --- # Pod 2: Medium training workload (2g.20gb) - can run on SAME GPU as Pod 1 apiVersion: v1 kind: Pod metadata: name: mig-medium-training-pod namespace: mig-gpu labels: app: mig-medium-training workload-type: training spec: restartPolicy: Never containers: - name: medium-training-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "/scripts/medium-training-script.py"] volumeMounts: - name: script-volume mountPath: /scripts readOnly: true resources: claims: - name: mig-medium-claim resourceClaims: - name: mig-medium-claim resourceClaimTemplateName: mig-medium-template nodeSelector: node.kubernetes.io/instance-type: p4de.24xlarge nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule volumes: - name: script-volume configMap: name: mig-scripts-configmap defaultMode: 0755 --- # Pod 3: Small inference workload (1g.10gb) - can run on SAME GPU as Pod 1 & 2 apiVersion: v1 kind: Pod metadata: name: mig-small-inference-pod namespace: mig-gpu labels: app: mig-small-inference workload-type: inference spec: restartPolicy: Never containers: - name: small-inference-container image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["python", "/scripts/small-inference-script.py"] volumeMounts: - name: script-volume mountPath: /scripts readOnly: true resources: claims: - name: mig-small-claim resourceClaims: - name: mig-small-claim resourceClaimTemplateName: mig-small-template nodeSelector: node.kubernetes.io/instance-type: p4de.24xlarge nvidia.com/gpu.present: "true" tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule volumes: - name: script-volume configMap: name: mig-scripts-configmap defaultMode: 0755
  5. Aplique essa especificação, que deve implantar três pods:

    kubctl apply -f mig-pod.yaml

    Esses pods devem ser programados pelo driver do DRA.

  6. Verifique os registros do Pod do driver DRA e você verá uma saída semelhante a esta:

    I0717 21:50:22.925811 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:22.932499 1 driver.go:129] Returning newly prepared devices for claim '933e9c72-6fd6-49c5-933c-a896407dc6d1': [&Device{RequestNames:[mig-large],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-0-mig-9-4-4,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-0-mig-9-4-4**],}] I0717 21:50:23.186472 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:23.191226 1 driver.go:129] Returning newly prepared devices for claim '61e5ddd2-8c2e-4c19-93ae-d317fecb44a4': [&Device{RequestNames:[mig-medium],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-2-mig-14-0-2,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-2-mig-14-0-2**],}] I0717 21:50:23.450024 1 driver.go:87] NodePrepareResource is called: number of claims: 1 I0717 21:50:23.455991 1 driver.go:129] Returning newly prepared devices for claim '1eda9b2c-2ea6-401e-96d0-90e9b3c111b5': [&Device{RequestNames:[mig-small],PoolName:ip-100-64-173-145.ec2.internal,DeviceName:gpu-1-mig-19-2-1,CDIDeviceIDs:[k8s.gpu.nvidia.com/device=**gpu-1-mig-19-2-1**],}]
  7. Verifique o status do pod resourceclaims para ver o status:

    kubectl get resourceclaims -n mig-gpu -w

    A seguir está um exemplo de saída:

    NAME STATE AGE mig-large-training-pod-mig-large-claim-6dpn8 pending 0s mig-large-training-pod-mig-large-claim-6dpn8 pending 0s mig-large-training-pod-mig-large-claim-6dpn8 allocated,reserved 0s mig-medium-training-pod-mig-medium-claim-bk596 pending 0s mig-medium-training-pod-mig-medium-claim-bk596 pending 0s mig-medium-training-pod-mig-medium-claim-bk596 allocated,reserved 0s mig-small-inference-pod-mig-small-claim-d2t58 pending 0s mig-small-inference-pod-mig-small-claim-d2t58 pending 0s mig-small-inference-pod-mig-small-claim-d2t58 allocated,reserved 0s

    Como você pode ver, todos os pods foram movidos de pendentes para allocated,reserved pelo driver do DRA.

  8. Execute nvidia-smi a partir do nó. Você notará que três processadores Python estão em execução:

    root@ip-100-64-173-145 bin]# nvidia-smi +-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 570.158.01 Driver Version: 570.158.01 CUDA Version: 12.8 | |-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA A100-SXM4-80GB On | 00000000:10:1C.0 Off | On | | N/A 63C P0 127W / 400W | 569MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 1 NVIDIA A100-SXM4-80GB On | 00000000:10:1D.0 Off | On | | N/A 56C P0 121W / 400W | 374MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 2 NVIDIA A100-SXM4-80GB On | 00000000:20:1C.0 Off | On | | N/A 63C P0 128W / 400W | 467MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 3 NVIDIA A100-SXM4-80GB On | 00000000:20:1D.0 Off | On | | N/A 57C P0 118W / 400W | 249MiB / 81920MiB | N/A Default | | | | Enabled | +-----------------------------------------+------------------------+----------------------+ | 4 NVIDIA A100-SXM4-80GB On | 00000000:90:1C.0 Off | 0 | | N/A 51C P0 77W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 5 NVIDIA A100-SXM4-80GB On | 00000000:90:1D.0 Off | 0 | | N/A 46C P0 69W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 6 NVIDIA A100-SXM4-80GB On | 00000000:A0:1C.0 Off | 0 | | N/A 52C P0 74W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ | 7 NVIDIA A100-SXM4-80GB On | 00000000:A0:1D.0 Off | 0 | | N/A 47C P0 72W / 400W | 0MiB / 81920MiB | 0% Default | | | | Disabled | +-----------------------------------------+------------------------+----------------------+ +-----------------------------------------------------------------------------------------+ | MIG devices: | +------------------+----------------------------------+-----------+-----------------------+ | GPU GI CI MIG | Memory-Usage | Vol| Shared | | ID ID Dev | BAR1-Usage | SM Unc| CE ENC DEC OFA JPG | | | | ECC| | |==================+==================================+===========+=======================| | 0 2 0 0 | 428MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 2MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 3 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 0MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 9 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 0 10 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 0MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 5 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 0MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 13 0 2 | 161MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 2MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 1 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 0MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 5 0 1 | 289MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 2MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 13 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 2 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 1 0 0 | 107MiB / 40192MiB | 42 0 | 3 0 2 0 0 | | | 0MiB / 32767MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 5 0 1 | 71MiB / 19968MiB | 28 0 | 2 0 1 0 0 | | | 0MiB / 16383MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 13 0 2 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ | 3 14 0 3 | 36MiB / 9728MiB | 14 0 | 1 0 0 0 0 | | | 0MiB / 8191MiB | | | +------------------+----------------------------------+-----------+-----------------------+ +-----------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=========================================================================================| **| 0 2 0 64080 C python 312MiB | | 1 13 0 64085 C python 118MiB | | 2 5 0 64073 C python 210MiB |** +-----------------------------------------------------------------------------------------+

Otimize as cargas de trabalho da GPU com o IMEX usando GB2 100 instâncias P6e

O IMEX (Internode Memory Exchange) permite a comunicação coerente com a memória entre os nós para treinamento distribuído na NVIDIA 00. GB2 UltraClusters

Execute as etapas a seguir.

  1. Defina um ComputeDomain para treinamento de vários nós com um arquivo chamadoimex-compute-domain.yaml:

    apiVersion: resource.nvidia.com/v1beta1 kind: ComputeDomain metadata: name: distributed-training-domain namespace: default spec: numNodes: 2 channel: resourceClaimTemplate: name: imex-channel-template
  2. Defina um pod usando canais IMEX com um arquivo chamadoimex-pod.yaml:

    apiVersion: v1 kind: Pod metadata: name: imex-distributed-training namespace: default labels: app: imex-training spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: nvidia.com/gpu.clique operator: Exists containers: - name: distributed-training image: nvcr.io/nvidia/pytorch:25.04-py3 command: ["bash", "-c"] args: - | echo "=== IMEX Channel Verification ===" ls -la /dev/nvidia-caps-imex-channels/ echo "" echo "=== GPU Information ===" nvidia-smi echo "" echo "=== NCCL Test (if available) ===" python -c " import torch import torch.distributed as dist import os print(f'CUDA available: {torch.cuda.is_available()}') print(f'CUDA device count: {torch.cuda.device_count()}') if torch.cuda.is_available(): for i in range(torch.cuda.device_count()): print(f'GPU {i}: {torch.cuda.get_device_name(i)}') # Check for IMEX environment variables imex_vars = [k for k in os.environ.keys() if 'IMEX' in k or 'NVLINK' in k] if imex_vars: print('IMEX Environment Variables:') for var in imex_vars: print(f' {var}={os.environ[var]}') print('IMEX channel verification completed') " # Keep container running for inspection sleep 3600 resources: claims: - name: imex-channel-0 - name: imex-channel-1 resourceClaims: - name: imex-channel-0 resourceClaimTemplateName: imex-channel-template - name: imex-channel-1 resourceClaimTemplateName: imex-channel-template tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule
    nota

    Isso requer instâncias P6e GB2 00.

  3. Implante o IMEX aplicando os modelos ComputeDomain e:

    kubectl apply -f imex-claim-template.yaml kubectl apply -f imex-compute-domain.yaml kubectl apply -f imex-pod.yaml
  4. Verifique o ComputeDomain status.

    kubectl get computedomain distributed-training-domain
  5. Monitore a implantação do daemon IMEX.

    kubectl get pods -n nvidia-dra-driver -l [resource.nvidia.com/computeDomain](http://resource.nvidia.com/computeDomain)
  6. Verifique os canais IMEX no Pod:

    kubectl exec imex-distributed-training -- ls -la /dev/nvidia-caps-imex-channels/
  7. Veja os registros do pod:

    kubectl logs imex-distributed-training

    Veja a seguir um exemplo da saída esperada:

    === IMEX Channel Verification === total 0 drwxr-xr-x. 2 root root 80 Jul 8 10:45 . drwxr-xr-x. 6 root root 380 Jul 8 10:45 .. crw-rw-rw-. 1 root root 241, 0 Jul 8 10:45 channel0 crw-rw-rw-. 1 root root 241, 1 Jul 8 10:45 channel1

Para obter mais informações, consulte o exemplo da NVIDIA em. GitHub