Nesta página, mostramos como maximizar a largura de banda e a capacidade de processamento para cargas de trabalho da GPU de alto desempenho nos clusters do Google Kubernetes Engine (GKE) no modo Standard. Esta página é destinada a engenheiros de machine learning (ML) e administradores de plataforma que facilitam cargas de trabalho de ML. Você já deve conhecer as tecnologias de rede, como placas de rede (NICs) e TCP, e com tecnologias de aceleradores, como a NVIDIA Collective Communications Library (NCCL).
Aplicativos de inteligência artificial (IA), ML e computação de alto desempenho (HPC) exigem aceleração poderosa para otimizar o desempenho, reduzindo os tempos de conclusão de jobs. Por exemplo, os modelos de ML que se concentram em IA de conversação e geração de imagens exigem alta escalonabilidade e poder de computação.
Sobre os supercomputadores de GPU do Google Cloud
O Google Cloud tem supercomputadores otimizados para aceleradores que são desenvolvidos para modelos grandes e escalonáveis. Essas máquinas têm os seguintes benefícios:
- Oito GPUs NVIDIA H100 por máquina.
- Até 200 Gbps de largura de banda na placa de rede (NIC) principal.
- Até quatro NICs secundárias, cada uma com suporte de largura de banda de até 200 Gbps para transferência de dados de GPU.
Para uma lista completa de benefícios, consulte a série de máquinas A3 na documentação do Compute Engine.
Sua carga de trabalho do GKE precisa usar todas as GPUs e NICs secundárias disponíveis em um único nó e usar uma parte significativa da largura de banda disponível. A solução descrita neste documento é ideal para cargas de trabalho que exigem alto desempenho, alta capacidade de processamento e baixa latência.
Recursos e funcionalidades necessários para maximizar a largura de banda
Para maximizar a largura de banda da rede nos nós de supercomputadores da GPU, use todos os recursos a seguir:
- GPUDirect-TCPX: reduz a sobrecarga necessária para transferir payloads de pacotes de e para GPUs, o que melhora significativamente a capacidade de processamento em escala em comparação com as GPUs que não usam GPUDirect-TCPX.
- gVNIC: ativa os recursos do GPUDirect-TCPX, como divisão de cabeçalho de pacote, direcionamento de fluxo e gerenciamento de buffer. A gVNIC é necessária para usar o GPUDirect-TCPX. Para detalhes sobre a gVNIC, consulte Aumentar a velocidade do tráfego de rede para nós da GPU.
- Várias redes: adicione NICs secundárias à máquina otimizada para aceleradores. Para máquinas A3, mais quatro NICs são adicionadas. Cada placa de rede é associada a uma sub-rede separada na própria VPC para evitar conflitos. Para detalhes sobre o suporte a várias redes, consulte Configurar o suporte a várias redes para pods.
- Políticas de posicionamento: use uma política de posicionamento de recursos para colocar todos os nós da GPU em uma carga de trabalho específica em servidores fisicamente próximos a fim de minimizar a latência. Para mais detalhes, consulte Definir um posicionamento compacto para nós do GKE.
Descrição do procedimento
Para usar todos esses recursos juntos, faça o seguinte:
- Crie nuvens privadas virtuais (VPC) e sub-redes
- Crie o ambiente do GKE:
- Crie um cluster com várias redes ativado
- Crie um pool de nós com estas características:
- gVNIC ativada
- Sub-redes de várias redes especificadas para cada placa de rede (NIC) secundária
- Série de máquinas A3 com GPUs H100 (quatro NICs secundárias e oito GPUs) que oferecem suporte aos nós
- Drivers da NVIDIA instalados mais recentes
- Instale o binário GPUDirect-TCPX e o plug-in NCCL.
- Implante uma carga de trabalho de teste para verificar a configuração do GPUDirect-TCPX
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
.
- Verifique se você tem cota suficiente para GPUs H100. Para solicitar mais cotas, consulte as cotas de GPU.
Requisitos
- O GPUDirect-TCPX é compatível com o GKE versão 1.27 ou mais recente e requer:
- Para a versão 1.27 do GKE, use a versão de patch do GKE 1.27.7-gke.1121000 ou mais recente.
- Para a versão 1.28 do GKE, use a versão de patch do GKE 1.28.8-gke.1095000 ou mais recente.
- Para a versão 1.29 do GKE, use a versão de patch do GKE 1.29.3-gke.1093000 ou mais recente.
- Os nós da GPU precisam usar o driver da NVIDIA versão 535 ou mais recente.
- É preciso usar o GKE Dataplane V2.
Limitações
Considere as seguintes limitações:
- Não é possível usar o GPUDirect-TCPX em clusters do Autopilot
- Só é possível usar o GPUDirect-TCPX na versão 1.27 ou posterior do GKE e com as seguintes versões de patch:
- Para a versão 1.27 do GKE, use a versão de patch do GKE 1.27.7-gke.1121000 ou mais recente.
- Para a versão 1.28 do GKE, use a versão de patch do GKE 1.28.8-gke.1095000 ou mais recente.
- Para a versão 1.29 do GKE, use a versão de patch do GKE 1.29.3-gke.1093000 ou mais recente.
- Não é possível usar o GPUDirect-TCPX com GPUs de várias instâncias ou compartilhamento de tempo de GPU.
- Não é possível usar o NCCL FastSocket
- Seu ambiente precisa ser compatível com a configuração
hostNetwork: true
na especificação do pod Se quiser usar SSDs locais para armazenamento de pods, especifique explicitamente o número exato de SSDs locais que serão anexados à VM do A3 usando a sinalização
--ephemeral-storage-local-ssd=count=SSD_COUNT
para armazenamento temporário ou o sinalização--local-nvme-ssd-block=count=SSD_COUNT
para bloquear o acesso. Se você omitir essa sinalização, não será possível usar os SSDs locais nos pods. Essas sinalizações serão necessárias apenas se você quiser usar o SSD local para acesso aos dados.O tamanho de máquina compatível no GKE é
a3-highgpu-8g
, e a contagem de SSD local correspondente é16
.
Criar VPCs e sub-redes
Crie redes VPC separadas no seu projeto para cada placa de rede virtual que você adicionar aos nós. Cada VPC precisa ter uma sub-rede e uma regra de firewall que permita o tráfego de rede interno. Para maximizar a largura de banda, recomendamos que você crie quatro novas redes.
Atualize a sub-rede VPC padrão no projeto para adicionar intervalos de endereços IP secundários para pods e serviços:
gcloud compute networks subnets update DEFAULT_NETWORK \ --region=REGION \ --add-secondary-ranges="CLUSTER_NAME-pods=POD_IP_ADDRESS_RANGE,CLUSTER_NAME-services=SERVICE_IP_ADDRESS_RANGE"
Substitua:
DEFAULT_NETWORK
: o nome da sub-rede padrão no projeto.REGION
: a região da sub-rede padrão.CLUSTER_NAME
: o nome do cluster do GKE.POD_IP_ADDRESS_RANGE
: o intervalo de endereços IP para os pods no cluster, na notação CIDR. Por exemplo,10.64.0.0/19
.SERVICE_IP_ADDRESS_RANGE
: o intervalo de endereços IP para os serviços no cluster usar, na notação CIDR. Precisa ser diferente do intervalo de pods. Por exemplo,10.65.0.0/19
.
Crie as redes VPC para GPUDirect-TCPX no projeto, cada uma com uma sub-rede e uma regra de firewall:
for N in $(seq 1 4); do gcloud compute networks create PROJECT_ID-net-$N \ --subnet-mode=custom \ --mtu=8244 gcloud compute networks subnets create PROJECT_ID-sub-$N \ --network=PROJECT_ID-net-$N \ --region=REGION \ --range=SUBNET_RANGE gcloud compute firewall-rules create PROJECT_ID-internal-$N \ --network=PROJECT_ID-net-$N \ --action=ALLOW \ --rules=tcp:0-65535,udp:0-65535,icmp \ --source-ranges=SOURCE_RANGE done
Substitua:
PROJECT_ID
: é seu ID do projeto no Google Cloud.REGION
: a região do Compute Engine para cada sub-rede.SUBNET_RANGE
: o intervalo de endereços IP de cada sub-rede na notação CIDR. Este comando de exemplo faz a iteração de quatro sub-redes. Portanto, use uma variável para alterar o endereço IP de cada sub-rede. Por exemplo, especifique192.168.$N.0/24
para que a primeira sub-rede use192.168.1.0/24
, a segunda use192.168.2.0/24
etc.SOURCE_RANGE
: o intervalo de endereços IP de origem para que a regra de firewall permita o tráfego de entrada, na notação CIDR. Por exemplo,192.168.0.0/16
.
Verifique se as redes foram criadas:
gcloud compute networks list
Crie o ambiente do GKE
Crie um novo cluster do GKE que use várias redes (pré-lançamento) e crie um pool de nós de GPU que usa máquinas A3 com GPUs H100 anexadas e quatro NICs adicionais. Não é possível atualizar um cluster atual para usar várias redes.
Crie um cluster:
gcloud container clusters create CLUSTER_NAME \ --location=LOCATION \ --cluster-version=VERSION \ --enable-dataplane-v2 --enable-ip-alias \ --enable-multi-networking \ --no-enable-autoupgrade \ --cluster-secondary-range-name=CLUSTER_NAME-pods \ --services-secondary-range-name=CLUSTER_NAME-services
Substitua:
CLUSTER_NAME
: o nome do novo cluster;LOCATION
: a região do Compute Engine para o cluster.VERSION
: a versão do GKE para o cluster. Precisa ser uma versão compatível, conforme descrito na seção "Requisitos".
Esse comando também especifica explicitamente o endereço IP secundário para pods e serviços para o cluster que você criou na seção anterior.
Crie recursos de rede e GKENetworkParamSet no cluster que correspondem às redes e sub-redes VPC que você criou:
kubectl apply -f - <<EOF apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc1 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc1 type: Device --- apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc2 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc2 type: Device --- apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc3 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc3 type: Device --- apiVersion: networking.gke.io/v1 kind: Network metadata: name: vpc4 spec: parametersRef: group: networking.gke.io kind: GKENetworkParamSet name: vpc4 type: Device --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc1 spec: vpc: PROJECT_ID-net-1 vpcSubnet: PROJECT_ID-sub-1 deviceMode: NetDevice --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc2 spec: vpc: PROJECT_ID-net-2 vpcSubnet: PROJECT_ID-sub-2 deviceMode: NetDevice --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc3 spec: vpc: PROJECT_ID-net-3 vpcSubnet: PROJECT_ID-sub-3 deviceMode: NetDevice --- apiVersion: networking.gke.io/v1 kind: GKENetworkParamSet metadata: name: vpc4 spec: vpc: PROJECT_ID-net-4 vpcSubnet: PROJECT_ID-sub-4 deviceMode: NetDevice EOF
Esses recursos orientam o GKE a configurar as placas de rede (NICs) para o tráfego da GPU no modo de passagem. O GKE não aplica a programação de rede integrada usando eBPF a esse tráfego.
Crie um pool de nós para as GPUs H100:
gcloud container node-pools create NODE_POOL_NAME \ --cluster=CLUSTER_NAME \ --location=LOCATION \ --machine-type=a3-highgpu-8g \ --accelerator=type=nvidia-h100-80gb,count=8,gpu-driver-version=LATEST \ --additional-node-network=network=PROJECT_ID-net-1,subnetwork=PROJECT_ID-sub-1 \ --additional-node-network=network=PROJECT_ID-net-2,subnetwork=PROJECT_ID-sub-2 \ --additional-node-network=network=PROJECT_ID-net-3,subnetwork=PROJECT_ID-sub-3 \ --additional-node-network=network=PROJECT_ID-net-4,subnetwork=PROJECT_ID-sub-4 \ --enable-gvnic \ --no-enable-autoupgrade \ [--ephemeral-storage-local-ssd=count=16]
Substitua
NODE_POOL_NAME
pelo nome do pool de nós.Se esse comando falhar, talvez você não tenha cota suficiente de GPU H100 no projeto. Verifique se você tem cota e tente executar o comando novamente.
Confira uma lista de nós no cluster:
kubectl get nodes
Verifique se cada nó da GPU tem oito GPUs:
kubectl describe node NODE_NAME
O resultado será assim:
Capacity: ... nvidia.com/gpu: 8 Allocatable: ... nvidia.com/gpu: 8
Instalar o GPUDirect-TCPX e configurar o NCCL
Esta seção mostra como instalar o binário GPUDirect-TCPX e um NCCL específico usando um DaemonSet.
Revise o manifesto de DaemonSet:
Esse DaemonSet faz o seguinte:
- Instala uma biblioteca NCCL e o binário GPUDirect-TCPX no nó.
- Armazena a biblioteca e o binário no diretório
/home/kubernetes/bin/nvidia/lib64
na VM. Por padrão, o GKE monta esse diretório no caminho/usr/local/nvidia/lib64
nos contêineres de GPU que precisam usar o NCCL e o GPUDirect-TCPX.
Implante o DaemonSet:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-tcpx-installer.yaml
O plug-in do NCCL leva aproximadamente dois minutos para começar a ser executado.
Verifique o status dos pods do DaemonSet:
kubectl get pods -n=kube-system -l=name=nccl-tcpx-installer
O resultado será assim:
nccl-tcpx-installer-6c2pv 1/1 Running 0 2m11s nccl-tcpx-installer-qgg82 1/1 Running 0 2m11s
Implantar uma carga de trabalho de teste
Nesta seção, você vai implantar uma carga de trabalho de amostra para verificar se o NCCL e o GPUDirect-TCPX funcionam conforme o esperado. Essa carga de trabalho inclui um contêiner de arquivo secundário chamado tcpx-daemon, que executa um serviço que permite ao pod usar o GPUDirect-TCPX. Você precisa adicionar esse contêiner de arquivo secundário a qualquer pod no seu próprio ambiente que precise usar GPUDirect-TCPX. Para ver um snippet dos campos obrigatórios a serem adicionados aos manifestos, consulte Adicionar GPUDirect-TCPX ao manifesto neste documento.
- Revise o manifesto ConfigMap
nccl-config-default.yaml
no GitHub. Esse manifesto implanta scripts que inicializam um teste NCCL allgather e define variáveis de ambiente específicas do NCCL. Revise o manifesto
nccl-test.yaml
no GitHub. Esse manifesto faz o seguinte:- Implanta dois pods, cada um executado em um nó que tem GPUs H100.
- Implanta um contêiner de arquivo secundário chamado
tcpx-daemon
em cada pod para permitir que esses pods usem o GPUDirect-TCPX.
Implante o ConfigMap e a carga de trabalho de teste:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-config-default.yaml kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-test.yaml
Execute os seguintes comandos para acionar um teste de todos os nós do NCCL:
head_pod=$(kubectl get pods --output='custom-columns=POD:.metadata.name' --no-headers | head -n1) nodes=($(kubectl get pods --output='custom-columns=NODE:.spec.nodeName' --no-headers)) kubectl exec --stdin --tty --container=nccl-test ${head_pod} -- /configs/allgather.sh ${nodes[@]}
O resultado será assim:
# out-of-place in-place # size count type redop root time algbw busbw #wrong time algbw busbw #wrong # (B) (elements) (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 1048576 16384 float none -1 696.8 1.50 1.41 0 729.0 1.44 1.35 0 2097152 32768 float none -1 776.4 2.70 2.53 0 726.7 2.89 2.71 0 4194304 65536 float none -1 774.3 5.42 5.08 0 805.1 5.21 4.88 0 8388608 131072 float none -1 812.1 10.33 9.68 0 817.6 10.26 9.62 0 16777216 262144 float none -1 1035.2 16.21 15.19 0 1067.8 15.71 14.73 0 33554432 524288 float none -1 1183.3 28.36 26.59 0 1211.8 27.69 25.96 0 67108864 1048576 float none -1 1593.4 42.12 39.49 0 1510.5 44.43 41.65 0 134217728 2097152 float none -1 2127.8 63.08 59.13 0 2312.7 58.03 54.41 0 268435456 4194304 float none -1 3603.0 74.50 69.85 0 3586.2 74.85 70.17 0 536870912 8388608 float none -1 7101.7 75.60 70.87 0 7060.9 76.03 71.28 0 # Out of bounds values : 0 OK # Avg bus bandwidth : 29.8293
Usar variáveis de ambiente do NCCL para melhorar o desempenho
Também é possível definir variáveis de ambiente específicas para melhorar o desempenho
das cargas de trabalho que usam NCCL. O ConfigMap nccl-config-default.yaml
que você implanta na seção Implantar uma carga de trabalho de teste define algumas variáveis do NCCL por padrão. A configuração da variável é armazenada no script run-nccl.sh
no ConfigMap.
Para alterar as variáveis de ambiente do NCCL, implante um manifesto ConfigMap atualizado com variáveis modificadas. O manifesto nccl-config-latest.yaml
no GitHub contém todas as variáveis recomendadas com um script run-nccl.sh
atualizado.
O comando a seguir atualiza o ConfigMap atual que tem as variáveis padrão com o ConfigMap nccl-config-latest.yaml
atualizado:
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-tcpx/nccl-config-latest.yaml
O Kubernetes leva aproximadamente dois minutos para atualizar o ConfigMap.
Para verificar as variáveis de ambiente do NCCL, execute o seguinte comando:
head_pod=$(kubectl get pods --output='custom-columns=POD:.metadata.name' --no-headers | head -n1)
kubectl exec --stdin --tty --container=nccl-test ${head_pod} -- cat /configs/run-nccl.sh
Adicionar GPUDirect-TCPX aos seus manifestos
Esta seção fornece os campos obrigatórios que você precisa adicionar aos manifestos do Kubernetes para que seus pods usem o GPUDirect-TCPX.
Adicione os seguintes campos à especificação do pod:
spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet volumes: - name: libraries hostPath: path: /home/kubernetes/bin/nvidia/lib64 - name: tcpx-socket hostPath: path: /run/tcpx
Adicione o seguinte contêiner ao manifesto para executar o serviço tcpx-daemon:
- name: tcpx-daemon image: us-docker.pkg.dev/gce-ai-infra/gpudirect-tcpx/tcpgpudmarxd-dev:v2.0.9 command: - /tcpgpudmarxd/build/app/tcpgpudmarxd - --gpu_nic_preset - a3vm - --gpu_shmem_type - fd - --uds_path - /run/tcpx - --setup_param - \"--verbose 128 2 0 \" securityContext: privileged: true volumeMounts: - name: libraries mountPath: /usr/local/nvidia/lib64 - name: tcpx-socket mountPath: /run/tcpx env: - name: LD_LIBRARY_PATH value: /usr/local/nvidia/lib64
Adicione as seguintes montagens de volume a todos os contêineres que solicitarem GPUs:
volumeMounts: - name: tcpx-socket mountPath: /tmp - name: libraries mountPath: /usr/local/nvidia/lib64
Adicione a seguinte variável de ambiente a cada contêiner de GPU:
env: - name: LD_LIBRARY_PATH value: /usr/local/nvidia/lib64
Como opção, adicione variáveis de ambiente para configurar as opções da NCCL. Para mais detalhes, consulte a seção Usar variáveis de ambiente do NCCL para melhorar o desempenho deste documento.
Uma especificação de pod completa tem esta aparência:
apiVersion: v1
kind: Pod
metadata:
name: example-pod
labels:
name: example-pod
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: tcpx-daemon
image: us-docker.pkg.dev/gce-ai-infra/gpudirect-tcpx/tcpgpudmarxd-dev:v2.0.9
command:
- /tcpgpudmarxd/build/app/tcpgpudmarxd
- --gpu_nic_preset
- a3vm
- --gpu_shmem_type
- fd
- --uds_path
- /run/tcpx
- --setup_param
- \"--verbose 128 2 0 \"
securityContext:
privileged: true
volumeMounts:
- name: libraries
mountPath: /usr/local/nvidia/lib64
- name: tcpx-socket
mountPath: /run/tcpx
env:
- name: LD_LIBRARY_PATH
value: /usr/local/nvidia/lib64
- name: nccl-test
image: us-docker.pkg.dev/gce-ai-infra/gpudirect-tcpx/nccl-plugin-gpudirecttcpx:v3.1.2
imagePullPolicy: Always
command:
- /bin/sh
- -c
- "while true; do echo hello; sleep 1; done"
env:
- name: LD_LIBRARY_PATH
value: /usr/local/nvidia/lib64
volumeMounts:
- name: tcpx-socket
mountPath: /run/tcpx
- name: libraries
mountPath: /usr/local/nvidia/lib64
resources:
limits:
nvidia.com/gpu: 8
volumes:
- name: libraries
hostPath:
path: /home/kubernetes/bin/nvidia/lib64
- name: tcpx-socket
hostPath:
path: /run/tcpx