Partilhe GPUs com várias cargas de trabalho através do NVIDIA MPS

Esta página explica como usar o serviço multiprocessos (MPS) da CUDA para permitir que várias cargas de trabalho partilhem um único acelerador de hardware de GPU NVIDIA nos seus nós do Google Kubernetes Engine (GKE).

Vista geral

O MPS da NVIDIA é uma solução de partilha de GPU que permite que vários contentores partilhem um único hardware de GPU física da NVIDIA associado a um nó.

O MPS da NVIDIA baseia-se no serviço de vários processos da NVIDIA no CUDA. O MPS da NVIDIA é uma implementação alternativa e binariamente compatível da API CUDA concebida para permitir de forma transparente que as aplicações CUDA de vários processos cooperativos sejam executadas em simultâneo num único dispositivo de GPU.

Com o MPS da NVIDIA, pode especificar o número máximo de contentores partilhados de uma GPU física. Este valor determina a quantidade de potência da GPU física que cada contentor recebe, em termos das seguintes caraterísticas:

Para saber mais sobre como as GPUs são agendadas com o MPS da NVIDIA e quando deve usar o MPS da CUDA, consulte o artigo Acerca das soluções de partilha de GPUs no GKE.

Quem deve usar este guia

As instruções nesta secção aplicam-se a si se for uma das seguintes opções:

  • Administrador da plataforma: cria e gere um cluster do GKE, planeia os requisitos de infraestrutura e recursos, e monitoriza o desempenho do cluster.
  • Programador de aplicações: cria e implementa cargas de trabalho em clusters do GKE. Se quiser instruções para pedir NVIDIA MPS com GPUs, consulte o artigo Implemente cargas de trabalho que usam NVIDIA MPS com GPUs.

Requisitos

  • Versão do GKE: pode ativar a partilha de GPU com o NVIDIA MPS em clusters padrão do GKE que executam a versão 1.27.7-gke.1088000 e posterior do GKE.
  • Tipo de GPU: pode ativar o MPS da NVIDIA para todos os tipos de GPU NVIDIA.

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize-a. Se instalou anteriormente a CLI gcloud, execute o comando gcloud components update para obter a versão mais recente. As versões anteriores da CLI gcloud podem não suportar a execução dos comandos neste documento.
  • Certifique-se de que tem quota de GPU NVIDIA suficiente. Se precisar de mais quota, consulte o artigo Pedir um aumento da quota.
  • Planeie a capacidade da GPU com base nas necessidades de recursos das cargas de trabalho e na capacidade da GPU subjacente.
  • Reveja as limitações da NVIDIA MPS com GPUs.

Ative o MPS da NVIDIA com GPUs em clusters do GKE

Como administrador da plataforma, tem de ativar o MPS da NVIDIA com GPUs num cluster padrão do GKE. Em seguida, os programadores de aplicações podem implementar cargas de trabalho para usar o MPS da NVIDIA com GPUs. Para ativar o MPS da NVIDIA com GPUs no GKE, faça o seguinte:

  1. Ative o MPS da NVIDIA com GPUs num novo cluster do GKE.
  2. Instale os controladores do dispositivo GPU da NVIDIA (se necessário).
  3. Verifique os recursos da GPU disponíveis nos seus nós.

Ative o MPS da NVIDIA com GPUs num cluster do GKE

Pode ativar o MPS da NVIDIA com GPUs quando cria clusters padrão do GKE. O node pool predefinido no cluster tem a funcionalidade ativada. Continua a ter de ativar o MPS da NVIDIA com GPUs quando cria manualmente novos conjuntos de nós nesse cluster.

Crie um cluster com o MPS da NVIDIA ativado através da CLI do Google Cloud:

gcloud container clusters create CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --cluster-version=CLUSTER_VERSION \
    --machine-type=MACHINE_TYPE \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=mps,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

Substitua o seguinte:

  • CLUSTER_NAME: o nome do novo cluster.
  • CONTROL_PLANE_LOCATION: a localização do Compute Engine do plano de controlo do seu cluster. Indique uma região para clusters regionais ou uma zona para clusters zonais. O tipo de GPU que usa tem de estar disponível na região selecionada.
  • CLUSTER_VERSION: a versão do GKE para o painel de controlo e os nós do cluster. Use a versão 1.27.7-gke.1088000 ou posterior do GKE. Em alternativa, especifique um canal de lançamento com essa versão do GKE através da flag --release-channel=RELEASE_CHANNEL.
  • MACHINE_TYPE: o tipo de máquina do Compute Engine para os seus nós.
  • GPU_TYPE: o tipo de GPU, que tem de ser uma plataforma de GPU NVIDIA como nvidia-tesla-v100.
  • GPU_QUANTITY: o número de GPUs físicas a associar a cada nó no conjunto de nós predefinido.
  • CLIENTS_PER_GPU: o número máximo de contentores que podem partilhar cada GPU física.
  • DRIVER_VERSION: a versão do controlador NVIDIA a instalar. Pode ser uma das seguintes opções:
    • default: instale a versão predefinida do controlador para a sua versão do GKE.
    • latest: instale a versão do controlador mais recente disponível para a sua versão do GKE. Disponível apenas para nós que usam o SO otimizado para contentores.
    • disabled: ignorar a instalação automática de controladores. Tem de instalar manualmente um controlador depois de criar o conjunto de nós. Se omitir gpu-driver-version, esta é a opção predefinida.

Ative o MPS da NVIDIA com GPUs num novo conjunto de nós

Pode ativar o MPS da NVIDIA com GPUs quando cria manualmente novos conjuntos de nós num cluster do GKE. Crie um node pool com o NVIDIA MPS ativado através da CLI Google Cloud:

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --location=CONTROL_PLANE_LOCATION \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=mps,max-shared-clients-per-gpu=CONTAINER_PER_GPU,gpu-driver-version=DRIVER_VERSION

Substitua o seguinte:

  • NODEPOOL_NAME: o nome do novo conjunto de nós.
  • CLUSTER_NAME: o nome do seu cluster, que tem de executar a versão 1.27.7-gke.1088000 ou posterior do GKE.
  • CONTROL_PLANE_LOCATION: a localização do Compute Engine do plano de controlo do seu cluster. Indique uma região para clusters regionais ou uma zona para clusters zonais.
  • MACHINE_TYPE: o tipo de máquina do Compute Engine para os seus nós. Para GPUs A100, use um tipo de máquina A2. Para todas as outras GPUs, use um tipo de máquina N1.
  • GPU_TYPE: o tipo de GPU, que tem de ser uma plataforma de GPU NVIDIA como nvidia-tesla-v100.
  • GPU_QUANTITY: o número de GPUs físicas a associar a cada nó no conjunto de nós.
  • CONTAINER_PER_GPU: o número máximo de contentores que podem partilhar cada GPU física.
  • DRIVER_VERSION: a versão do controlador NVIDIA a instalar. Pode ser uma das seguintes opções:

    • default: instale a versão predefinida do controlador para a sua versão do GKE.
    • latest: instale a versão do controlador mais recente disponível para a sua versão do GKE. Disponível apenas para nós que usam o SO otimizado para contentores.
    • disabled: ignorar a instalação automática de controladores. Tem de instalar manualmente um controlador depois de criar o conjunto de nós. Se omitir gpu-driver-version, esta é a opção predefinida.

Instale os controladores de dispositivos da GPU NVIDIA

Se optou por desativar a instalação automática de controladores quando criou o cluster, ou se usar uma versão do GKE anterior a 1.27.2-gke.1200, tem de instalar manualmente um controlador NVIDIA compatível para gerir a divisão MPS da NVIDIA das GPUs físicas. Para instalar os controladores, implementa um DaemonSet de instalação do GKE que configura os controladores.

Para ver instruções, consulte o artigo Instalar controladores de dispositivos de GPU NVIDIA.

Verifique os recursos de GPU disponíveis

Pode verificar se o número de GPUs nos seus nós corresponde ao número que especificou quando ativou o NVIDIA MPS. Também pode verificar se o daemon de controlo do NVIDIA MPS está em execução.

Valide os recursos de GPU disponíveis nos seus nós

Para verificar os recursos da GPU disponíveis nos seus nós, execute o seguinte comando:

kubectl describe nodes NODE_NAME

Substitua NODE_NAME pelo nome do seu nó.

O resultado é semelhante ao seguinte:

...
Capacity:
  ...
  nvidia.com/gpu:             3
Allocatable:
  ...
  nvidia.com/gpu:             3

Neste resultado, o número de recursos de GPU no nó é 3 devido aos seguintes valores:

  • O valor em max-shared-clients-per-gpu é 3.
  • O número de GPUs físicas a anexar ao nó é 1.count Se o count de GPUs físicas fosse 2, o resultado mostraria 6 recursos de GPU alocáveis, três em cada GPU física.

Verifique se o daemon de controlo do MPS está em execução

O plug-in do dispositivo GPU executa uma verificação do estado de funcionamento no daemon de controlo do MPS. Quando o daemon de controlo do MPS está em bom estado, pode implementar um contentor.

Para verificar se o MPS está ativo, execute o seguinte comando:

kubectl logs -l k8s-app=nvidia-gpu-device-plugin -n kube-system --tail=100 | grep MPS

O resultado é semelhante ao seguinte:

I1118 08:08:41.732875       1 nvidia_gpu.go:75] device-plugin started
...
I1110 18:57:54.224832       1 manager.go:285] MPS is healthy, active thread percentage = 100.0
...

No resultado, pode ver que ocorreram os seguintes eventos:

  • O erro failed to start GPU device manager precede o erro MPS is healthy. Este erro é temporário. Se vir a mensagem MPS is healthy, significa que o daemon de controlo está em execução.
  • A mensagem active thread percentage = 100.0 significa que o recurso de GPU físico completo tem um segmento completamente ativo.

Implemente cargas de trabalho que usam o MPS

Como operador de aplicações que está a implementar cargas de trabalho de GPU, pode indicar ao GKE para partilhar unidades de partilha de MPS na mesma GPU física. No manifesto seguinte, pede uma GPU física e define max-shared-clients-per-gpu=3. A GPU física recebe três unidades de partilha de MPS e inicia uma tarefa nvidia/samples:nbody com três pods (contentores) em execução em paralelo.

  1. Guarde o manifesto como gpu-mps.yaml:

      apiVersion: batch/v1
      kind: Job
      metadata:
        name: nbody-sample
      spec:
        # Specifies the desired number of successfully finished Pods.
        completions: 3
        # Specifies the maximum desired number of Pods that should run at any given time.
        parallelism: 3
        template:
          spec:
            # Allows the Pod to share the host's IPC namespace.
            # The following field is required for containers to communicate with the MPS control daemon.
            hostIPC: true
            # Selects a node with the 'mps' GPU sharing strategy.
            nodeSelector:
              cloud.google.com/gke-gpu-sharing-strategy: mps
            containers:
              - name: nbody-sample
                # A sample CUDA application from NVIDIA.
                image: nvidia/samples:nbody
                # The command to run in the container.
                command: ["/tmp/nbody"]
                # Arguments for the command. Runs the nbody simulation in benchmark mode.
                args: ["-benchmark", "-i=5000"]
                resources:
                  limits:
                    # Requests one MPS sharing unit from a physical GPU.
                    nvidia.com/gpu: 1
            restartPolicy: "Never"
        backoffLimit: 1
    

    Neste manifesto:

    • hostIPC: true permite que os pods comuniquem com o daemon de controlo do MPS. É obrigatório. No entanto, tenha em atenção que a configuração hostIPC: true permite que o contentor aceda ao recurso do anfitrião, o que introduz riscos de segurança.
    • 5000 iterações executadas no modo de referência.
  2. Aplique o manifesto:

    kubectl apply -f gpu-mps.yaml
    
  3. Verifique se todos os pods estão em execução:

    kubectl get pods
    

    O resultado é semelhante ao seguinte:

    NAME                           READY   STATUS    RESTARTS   AGE
    nbody-sample-6948ff4484-54p6q   1/1     Running   0          2m6s
    nbody-sample-6948ff4484-5qs6n   1/1     Running   0          2m6s
    nbody-sample-6948ff4484-5zpdc   1/1     Running   0          2m5s
    
  4. Verifique os registos dos pods para validar se a tarefa foi concluída:

    kubectl logs -l job-name=nbody-sample -f
    

    O resultado é semelhante ao seguinte:

    ...
    > Compute 8.9 CUDA device: [NVIDIA L4]
    18432 bodies, total time for 5000 iterations: 9907.976 ms
    = 171.447 billion interactions per second
    = 3428.941 single-precision GFLOP/s at 20 flops per interaction
    ...
    

    Uma vez que o GKE executa 50 000 iterações, o registo pode demorar vários minutos.

Limpar

Elimine os trabalhos e todos os respetivos pods executando o seguinte comando:

kubectl delete job --all

Limite a memória do dispositivo fixada e o thread ativo com o NVIDIA MPS

Por predefinição, quando usa a GPU com o MPS da NVIDIA no GKE, as seguintes variáveis de ambiente CUDA são injetadas na carga de trabalho da GPU:

  • CUDA_MPS_ACTIVE_THREAD_PERCENTAGE: esta variável indica a percentagem de threads disponíveis que cada unidade de partilha de MPS pode usar. Por predefinição, cada unidade de partilha de MPS da GPU está definida como 100 / MaxSharedClientsPerGPU para receber uma parte igual do cálculo da GPU em termos de multiprocessador de streams.
  • CUDA_MPS_PINNED_DEVICE_MEM_LIMIT: esta variável limita a quantidade de memória da GPU que pode ser atribuída por uma unidade de partilha de MPS da GPU. Por predefinição, cada unidade de partilha de MPS da GPU está definida como total mem / MaxSharedClientsPerGPU para receber uma fatia igual da memória da GPU.

Para definir o limite de recursos para as cargas de trabalho da GPU, configure estas variáveis de ambiente do NVIDIA MPS:

  1. Reveja e crie a imagem do exemplo cuda-mps no GitHub.

  2. Guarde o seguinte manifesto como cuda-mem-and-sm-count.yaml:

    apiVersion: v1
    kind: Pod
    metadata:
      name: cuda-mem-and-sm-count
    spec:
      # Allows the Pod to share the host's IPC namespace.
      # The following field is required for containers to communicate with the MPS control daemon.
      hostIPC: true
      # Selects a node with the 'mps' GPU sharing strategy.
      nodeSelector:
        cloud.google.com/gke-gpu-sharing-strategy: mps
      containers:
        - name: cuda-mem-and-sm-count
          # The custom image built from the cuda-mps example.
          image: CUDA_MPS_IMAGE
          # Grants the container extended privileges on the host machine.
          securityContext:
            privileged: true
          resources:
            limits:
              # Requests one MPS sharing unit from a physical GPU.
              nvidia.com/gpu: 1
    

    Substitua CUDA_MPS_IMAGE pelo nome da imagem que criou para o exemplo cuda-mps.

    O MPS da NVIDIA requer que defina hostIPC:true nos agrupamentos. A configuração permite que o contentor aceda ao recurso do anfitrião, o que introduz riscos de segurança.hostIPC:true

  3. Aplique o manifesto:

    kubectl apply -f cuda-mem-and-sm-count.yaml
    
  4. Verifique os registos deste Pod:

    kubectl logs cuda-mem-and-sm-count
    

    Num exemplo que usa a NVIDIA Tesla L4 com gpu-sharing-strategy=mps e max-shared-clients-per-gpu=3, o resultado é semelhante ao seguinte:

    For device 0:  Free memory: 7607 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 18
    

    Neste exemplo, a GPU NVIDIA Tesla L4 tem 60 SMs e 24 GB de memória. Cada unidade de partilha de MPS recebe aproximadamente 33% de threads ativas e 8 GB de memória.

  5. Atualize o manifesto para pedir 2 nvidia.com/gpu:

      resources:
            limits:
              nvidia.com/gpu: 2
    

    O resultado é semelhante ao seguinte:

    For device 0:  Free memory: 15230 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 38
    
  6. Atualize o manifesto para substituir as variáveis CUDA_MPS_ACTIVE_THREAD_PERCENTAGE e CUDA_MPS_PINNED_DEVICE_MEM_LIMIT:

      env:
        - name: CUDA_MPS_ACTIVE_THREAD_PERCENTAGE
          value: "20"
        - name: CUDA_MPS_PINNED_DEVICE_MEM_LIMIT
          value: "0=8000M"
    

    O resultado é semelhante ao seguinte:

    For device 0:  Free memory: 7952 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 10
    

Limitações

  • O MPS em GPUs pré-Volta (P100) tem capacidades limitadas em comparação com os tipos de GPU em e após Volta.
  • Com o NVIDIA MPS, o GKE garante que cada contentor recebe memória do dispositivo fixada e um thread ativo limitados. No entanto, outros recursos, como a largura de banda da memória, os codificadores ou os descodificadores, não são capturados como parte destes limites de recursos. Como resultado, os contentores podem afetar negativamente o desempenho de outros contentores se todos estiverem a pedir o mesmo recurso ilimitado.
  • O NVIDIA MPS tem limitações de proteção de memória e contenção de erros. Recomendamos que avalie estas limitações para garantir a compatibilidade com as suas cargas de trabalho.
  • O MPS da NVIDIA requer que defina hostIPC:true nos agrupamentos. A configuração permite que o contentor aceda ao recurso do anfitrião, o que introduz riscos de segurança.hostIPC:true
  • O GKE pode rejeitar determinados pedidos de GPU quando usa o NVIDIA MPS para evitar um comportamento inesperado durante a atribuição de capacidade.
  • O número máximo de contentores que podem partilhar uma única GPU física com o NVIDIA MPS é 48 (a GPU pré-Volta só suporta 16). Ao planear a configuração do NVIDIA MPS, considere as necessidades de recursos das suas cargas de trabalho e a capacidade das GPUs físicas subjacentes para otimizar o desempenho e a capacidade de resposta.

O que se segue?