Compartilhar GPUs com várias cargas de trabalho usando o compartilhamento de tempo GPU


Nesta página, mostramos como permitir que várias cargas de trabalho tenham acesso compartilhado por tempo de GPU com um único acelerador de hardware da GPU NVIDIA® nos nós do Google Kubernetes Engine (GKE). Para saber mais sobre como o compartilhamento de tempo da GPU funciona, assim como as limitações e exemplos de quando usar o compartilhamento de tempo da GPU, consulte Compartilhamento de tempo da GPU no GKE.

Visão geral

O compartilhamento de tempode GPU é um recurso do GKE em que vários contêineres compartilham uma única GPU física anexada a um nó. O compartilhamento de tempo de GPU no GKE permite usar as GPUs conectadas de maneira mais eficiente e economizar custos de execução.

Quem precisa usar este guia

As instruções neste guia se aplicam a você se:

  • Administrador da plataforma: cria e gerencia um cluster do GKE, planeja requisitos de infraestrutura e recursos e monitora o desempenho do cluster.
  • Desenvolvedor de aplicativos: projeta e implanta cargas de trabalho em clusters do GKE. Se você quiser instruções para solicitar o compartilhamento de tempo da GPU, consulte Implantar cargas de trabalho que usam o compartilhamento de tempo da GPU.

Requisitos

  • Versão do GKE: é possível ativar o compartilhamento de tempo da GPU em clusters padrão do GKE que executam o GKE versão 1.23.7-gke.1400 e posterior. É possível usar GPUs de compartilhamento de tempo em clusters do Autopilot do GKE que executam o GKE versão 1.29.3-gke.1093000 e posterior.
  • Tipo de GPU: é possível ativar o compartilhamento de tempo de GPU em nós que usam tipos de GPU posteriores ao NVIDIA Tesla® K80.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a Google Cloud CLI para essa tarefa, instale e, em seguida, inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando gcloud components update.

Ativar o compartilhamento de tempo da GPU em clusters e pools de nós do GKE

Como administrador da plataforma, você precisa ativar o compartilhamento de tempo de GPU em um cluster do GKE Standard antes que os desenvolvedores possam implantar cargas de trabalho para usar as GPUs. Para ativar o compartilhamento de tempo de GPU, faça o seguinte:

  1. Ative o compartilhamento de tempo de GPU em um cluster do GKE.
  2. Instale os drivers de dispositivo da GPU NVIDIA (se necessário).
  3. Verifique os recursos da GPU disponíveis nos nós.

Os clusters do Autopilot que executam a versão 1.29.3-gke.1093000 e mais recentes ativam as GPUs de compartilhamento de tempo por padrão. O compartilhamento de tempo nos clusters do Autopilot é configurado na especificação da carga de trabalho. Para saber mais, consulte a seção Implantar cargas de trabalho que usam GPUs compartilhadas por tempo.

Ativar o compartilhamento de tempo da GPU em um cluster do GKE Standard

É possível ativar o compartilhamento de tempo da GPU ao criar clusters do GKE Standard. O pool de nós padrão no cluster tem o recurso ativado. Você ainda precisa ativar o compartilhamento de tempo de GPU ao criar manualmente novos pools de nós nesse cluster.

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

Substitua:

  • CLUSTER_NAME: o nome do novo cluster;
  • COMPUTE_REGION: a região do Compute Engine para o novo cluster. Para clusters de zona, especifique --zone=COMPUTE_ZONE.
  • CLUSTER_VERSION: a versão do GKE do plano e dos nós de controle do cluster. Use o GKE versão 1.23.7-gke.1400 ou posterior. Se preferir, especifique um canal de lançamento com essa versão do GKE usando a sinalização --release-channel=RELEASE_CHANNEL.
  • MACHINE_TYPE: o tipo de máquina do Compute Engine para os nós. Recomendamos que você selecione um tipo de máquina otimizado para aceleradores.
  • GPU_TYPE: o tipo de GPU, que precisa ser uma plataforma de GPU NVIDIA Tesla, como nvidia-tesla-v100.
  • GPU_QUANTITY: o número de GPUs físicas a serem anexadas a cada nó no pool de nós padrão.
  • CLIENTS_PER_GPU: o número máximo de contêineres que podem compartilhar cada GPU física.
  • DRIVER_VERSION: a versão do driver NVIDIA a ser instalado. Será um dos seguintes valores:
    • default: instale a versão padrão do driver para a versão do GKE.
    • latest: instale a versão mais recente disponível do driver para a versão do GKE. Disponível apenas para nós que usam o Container-Optimized OS.
    • disabled: pula a instalação automática do driver. Você precisa instalar manualmente um driver depois de criar o pool de nós. Se você omitir gpu-driver-version, essa será a opção padrão.

Ativar o compartilhamento de tempo da GPU em um pool de nós do GKE

É possível ativar o compartilhamento de tempo de GPU ao criar manualmente novos pools de nós em um cluster do GKE.

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --region=COMPUTE_REGION \
    --accelerator=type=GPU_TYPE,count=GPU_QUANTITY,gpu-sharing-strategy=time-sharing,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

Substitua:

  • NODEPOOL_NAME: o nome do novo pool de nós.
  • CLUSTER_NAME: o nome do cluster, que precisa executar a versão 1.23.7-gke.1400 ou posterior do GKE.
  • COMPUTE_REGION: a região do Compute Engine do cluster. Para clusters zonais, especifique --zone=COMPUTE_ZONE.
  • MACHINE_TYPE: o tipo de máquina do Compute Engine para os nós. Recomendamos que você selecione um tipo de máquina otimizado para aceleradores.
  • GPU_TYPE: o tipo de GPU, que precisa ser uma plataforma de GPU NVIDIA Tesla, como nvidia-tesla-v100.
  • GPU_QUANTITY: o número de GPUs físicas a serem anexadas a cada nó no pool de nós.
  • CLIENTS_PER_GPU: o número máximo de contêineres que podem compartilhar cada GPU física.
  • DRIVER_VERSION: a versão do driver NVIDIA a ser instalado. Será um dos seguintes valores:

    • default: instale a versão padrão do driver para a versão do GKE.
    • latest: instale a versão mais recente disponível do driver para a versão do GKE. Disponível apenas para nós que usam o Container-Optimized OS.
    • disabled: pula a instalação automática do driver. Você precisa instalar manualmente um driver depois de criar o pool de nós. Se você omitir gpu-driver-version, essa será a opção padrão.

Instalar drivers de dispositivo da GPU NVIDIA

Antes de continuar, conecte-se ao cluster executando o seguinte comando:

gcloud container clusters get-credentials CLUSTER_NAME

Se você optar por desativar a instalação automática de drivers ao criar o cluster ou usar uma versão do GKE anterior a 1.27.2-gke.1200, instale manualmente um driver NVIDIA compatível para gerenciar a divisão de compartilhamento de tempo das GPUs físicas. Para instalar os drivers, implante um DaemonSet de instalação do GKE.

Para instruções, consulte Como instalar drivers de dispositivo da GPU NVIDIA.

Se você planeja usar o provisionamento automático de nós no cluster, também precisa configurar o provisionamento automático de nós com os escopos que permitem que o GKE instale os drivers de dispositivos da GPU para você. Para instruções, consulte Como usar o provisionamento automático de nós com GPUs.

Verifique os recursos de GPU disponíveis nos nós

Para verificar se o número de GPUs visíveis nos nós corresponde ao número especificado quando você ativou o compartilhamento de tempo de GPU, descreva os nós:

kubectl describe nodes NODE_NAME

O resultado será assim:

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

Neste exemplo de saída, o número de recursos de GPU no nó é 3 porque o valor especificado para max-shared-clients-per-gpu era 3 e o count de GPUs físicas para anexar ao nó foi 1. Outro exemplo: se o count das GPUs físicas fosse 2, a saída mostraria 6 recursos de GPU alocáveis, três em cada GPU física.

Implantar cargas de trabalho que usam o compartilhamento de tempo de GPU

Como um operador de aplicativo que está implantando cargas de trabalho de GPU, é possível selecionar o compartilhamento de tempo de GPU ativado especificando os rótulos de nó apropriados em um nodeSelector nos manifestos. Ao planejar suas solicitações, analise os limites de solicitações para garantir que o GKE não rejeite suas implantações.

Para implantar uma carga de trabalho para consumir o compartilhamento de tempo da GPU, siga estas etapas:

  1. Adicione um nodeSelector ao manifesto do pod para os seguintes rótulos:

    • cloud.google.com/gke-gpu-sharing-strategy: time-sharing: seleciona nós que usam o compartilhamento de tempo da GPU.
    • cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU": seleciona nós que permitem que um número específico de contêineres compartilhem a GPU subjacente.
  2. Adicione a solicitação de recurso da GPU nvidia.com/gpu=1 à especificação do contêiner em spec.containers.resources.limits.

Por exemplo, as etapas a seguir mostram como implantar três pods em um pool de nós de compartilhamento de tempo de GPU. O GKE aloca cada contêiner na mesma GPU física. Os contêineres imprimem o UUID da GPU conectada a esse contêiner.

  1. Salve o seguinte manifesto como gpu-timeshare.yaml:

Autopilot

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: cuda-simple
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: cuda-simple
          template:
            metadata:
              labels:
                app: cuda-simple
            spec:
              nodeSelector:
                cloud.google.com/gke-accelerator: "GPU_TYPE"
                cloud.google.com/gke-gpu-sharing-strategy: "time-sharing"
                cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU"
                cloud.google.com/gke-accelerator-count: "GPU_COUNT"
              containers:
              - name: cuda-simple
                image: nvidia/cuda:11.0.3-base-ubi7
                command:
                - bash
                - -c
                - |
                  /usr/local/nvidia/bin/nvidia-smi -L; sleep 300
                resources:
                  limits:
                    nvidia.com/gpu: 1
      

Substitua:

  • GPU_TYPE: o tipo de GPU.
  • CLIENTS_PER_GPU: o número de cargas de trabalho que usarão essa GPU. Neste exemplo, use 3.
  • GPU_COUNT: número de GPUs a serem anexadas ao nó Neste exemplo, use 1.

Standard

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: cuda-simple
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: cuda-simple
          template:
            metadata:
              labels:
                app: cuda-simple
            spec:
              nodeSelector:
                cloud.google.com/gke-gpu-sharing-strategy: "SHARING_STRATEGY"
                cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU"
              containers:
              - name: cuda-simple
                image: nvidia/cuda:11.0.3-base-ubi7
                command:
                - bash
                - -c
                - |
                  /usr/local/nvidia/bin/nvidia-smi -L; sleep 300
                resources:
                  limits:
                    nvidia.com/gpu: 1
      

Substitua:

  • SHARING_STRATEGY com "compartilhamento de tempo" para solicitar o compartilhamento de tempo para a GPU.
  • CLIENTS_PER_GPU: o número de cargas de trabalho que usarão essa GPU. Neste exemplo, use 3.
  1. Aplique o manifesto:

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

    kubectl get pods -l=app=cuda-simple
    
  3. Verifique os registros de qualquer pod para ver o UUID da GPU:

    kubectl logs POD_NAME
    

    O resultado será assim:

    GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-0771302b-eb3a-6756-7a23-0adcae8efd47)
    
  4. Se os nós tiverem uma GPU física anexada, verifique os registros de qualquer outro pod no mesmo nó para verificar se o UUID da GPU é o mesmo:

    kubectl logs POD2_NAME
    

    O resultado será assim:

    GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-0771302b-eb3a-6756-7a23-0adcae8efd47)
    

Use o compartilhamento de tempo de GPU com GPUs de várias instâncias

Como administrador da plataforma, você pode combinar vários recursos de GPU do GKE. O compartilhamento de tempo de GPU funciona com GPUs de várias instâncias, que particionam uma única GPU física em até sete frações. Essas partições são isoladas umas das outras. É possível configurar o compartilhamento de tempo de GPU para cada partição de GPU de várias instâncias.

Por exemplo, se você definir gpu-partition-size como 1g.5gb, a GPU subjacente será dividida em sete partições. Se você também definir max-shared-clients-per-gpu como 3, cada partição aceitará até três contêineres, totalizando até 21 dispositivos de compartilhamento de tempo de GPU disponíveis para alocar nessa GPU física. Para saber como o gpu-partition-size é convertido em partições reais, consulte Partições da GPU de várias instâncias.

Para criar um cluster de GPU de várias instâncias com o compartilhamento de tempo de GPU ativado, execute o seguinte comando:

Autopilot

Com o Autopilot, o compartilhamento de tempo de GPU e as GPUs de várias instâncias podem ser usadas juntas com os dois conjuntos de seletores de nós.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cuda-simple
spec:
  replicas: 7
  selector:
    matchLabels:
      app: cuda-simple
  template:
    metadata:
      labels:
        app: cuda-simple
    spec:
      nodeSelector:
        cloud.google.com/gke-gpu-partition-size: 1g.5gb
        cloud.google.com/gke-gpu-sharing-strategy: time-sharing
        cloud.google.com/gke-max-shared-clients-per-gpu: "3"
        cloud.google.com/gke-accelerator: nvidia-tesla-a100
        cloud.google.com/gke-accelerator-count: "1"
      containers:
      - name: cuda-simple
        image: nvidia/cuda:11.0.3-base-ubi7
        command:
        - bash
        - -c
        - |
          /usr/local/nvidia/bin/nvidia-smi -L; sleep 300
        resources:
          limits:
            nvidia.com/gpu: 1

Padrão

Com a opção padrão, você precisa criar um cluster de várias instâncias e tempo de GPU compartilhado executando o seguinte comando:

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --machine-type=MACHINE_TYPE \
    --region=COMPUTE_REGION \
    --accelerator=type=nvidia-tesla-a100,count=GPU_QUANTITY,gpu-partition-size=PARTITION_SIZE,gpu-sharing-strategy=time-sharing,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

Substitua PARTITION_SIZE pelo tamanho da partição da GPU de várias instâncias que você quer, como 1g.5gb.

Limitações

  • Com o compartilhamento de tempo de GPU, o GKE aplica o isolamento de espaço de endereço, de desempenho e de erro entre contêineres que compartilham uma GPU física. No entanto, os limites de memória não são aplicados às GPUs. Para evitar problemas de falta de memória (OOM, na sigla em inglês), defina os limites de memória da GPU nas carga de trabalho. Para evitar problemas de segurança, implante apenas cargas de trabalho que estejam no mesmo limite de confiança para o compartilhamento de tempo da GPU.
  • Para evitar comportamentos inesperados durante a alocação de capacidade, o GKE pode rejeitar determinadas solicitações de compartilhamento de tempo da GPU. Para mais detalhes, consulte Solicitações de GPU para compartilhamento de tempo de GPU.
  • O número máximo de contêineres que podem usar o compartilhamento de tempo em uma única GPU física é 48. Ao planejar a configuração de compartilhamento de tempo de GPU, considere as necessidades de recursos das cargas de trabalho e a capacidade das GPUs físicas subjacentes para otimizar o desempenho e a capacidade de resposta.

A seguir