I workload di AI e ML richiedono una comunicazione significativa tra i pod. A causa di questo requisito, la larghezza di banda della rete tra i pod influisce direttamente sul tempo di esecuzione e sul costo del workload. Questa larghezza di banda dipende dal posizionamento delle istanze di macchine virtuali (VM) nel cluster.
Questo documento spiega come ottimizzare la pianificazione dei workload di AI o ML su larga scala in un cluster Google Kubernetes Engine (GKE) per prestazioni e affidabilità. In particolare, configurerai il cluster in modo che utilizzi la pianificazione sensibile alla topologia (TAS) per la comunicazione a bassa latenza. Questo approccio riduce al minimo il sovraccarico di comunicazione e contribuisce a massimizzare le prestazioni dei workload.
Che cos'è la pianificazione sensibile alla topologia (TAS)?
TAS può migliorare significativamente l'efficienza dell'addestramento dei modelli linguistici di grandi dimensioni (LLM). La TAS posiziona strategicamente i worker nella topologia di rete per ridurre al minimo il sovraccarico di comunicazione durante l'aggregazione dei gradienti, che richiede che i worker comunichino in un ordine di rango specifico. Riducendo al minimo gli hop di rete tra i worker che comunicano in sequenza, la TAS riduce la contesa di rete e ottimizza l'utilizzo della larghezza di banda, con conseguente convergenza più rapida e tempi di addestramento più brevi. Con modelli LLM sempre più grandi, la TAS è essenziale per massimizzare le prestazioni e la scalabilità dell'addestramento distribuito.
La TAS funziona al meglio con la capacità posizionata in modo denso, che può essere ottenuta tramite le prenotazioni. Con le VM con avvio flessibile o le VM spot, è meno probabile che la capacità venga allocata in modo ravvicinato, quindi la TAS potrebbe non funzionare bene in questo scenario.
Prima di iniziare
Prima di iniziare, assicurati di aver eseguito le seguenti attività:
- Abilita l'API Google Kubernetes Engine. Abilita l'API Google Kubernetes Engine
- Se vuoi utilizzare Google Cloud CLI per questa attività,
installala e poi
inizializza gcloud CLI. Se hai già installato gcloud CLI, scarica l'ultima
versione eseguendo il
gcloud components updatecomando. Le versioni precedenti di gcloud CLI potrebbero non supportare l'esecuzione dei comandi in questo documento.
Per connetterti al cluster, esegui questo comando:
gcloud container clusters get-credentials CLUSTER_NAMESostituisci
CLUSTER_NAMEcon il nome del cluster.
Prepara il cluster GKE
Per preparare il cluster GKE all'esecuzione dei workload con la TAS, completa i seguenti passaggi:
Installa Kueue con la TAS abilitata
Ti consigliamo di utilizzare la TAS con
Kueue, un sistema nativo di Kubernetes
che gestisce le quote e il modo in cui i job dovrebbero utilizzarle. La TAS richiede Kueue versione 0.10.0 o successive e devi abilitarla esplicitamente.
Per installare Kueue e abilitare la TAS, seleziona una delle seguenti opzioni:
Manifest Kueue
Installa Kueue:
kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.10.0/manifests.yamlAbilita la TAS in Kueue:
kubectl -n kueue-system patch deployment kueue-controller-manager \ --type json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=TopologyAwareScheduling=true"}]'
Grafico Helm
Installa Kueue con la TAS abilitata utilizzando un grafico Helm:
helm install kueue oci://us-central1-docker.pkg.dev/k8s-staging-images/charts/kueue \
--version="v0.10.0" \
--create-namespace \
--namespace=kueue-system \
--set="controllerManager.featureGates[0].name=TopologyAwareScheduling,controllerManager.featureGates[0].enabled=true"
Dopo aver installato Kueue, devi configurarlo in modo che comprenda l'infrastruttura che gestisce, come spiegato nella sezione successiva.
Visualizza la topologia del cluster GKE
Prima di visualizzare la topologia dei nodi A4X, A4, A3 Ultra, A3 Mega e A3 High (8 GPU) di cui è stato eseguito il provisioning come VM spot, devi definire il posizionamento compatto sui nodi GKE per esporre la relativa topologia fisica per la TAS. In caso contrario, si verificano errori.
Per visualizzare la topologia dei nodi del cluster GKE in un pool di nodi specifico, esegui questo comando:
kubectl get nodes -l cloud.google.com/gke-nodepool=NODE_POOL_NAME \
-ocustom-columns='NAME:.metadata.name,BLOCK:.metadata.labels.cloud\.google\.com/gce-topology-block,SUBBLOCK:.metadata.labels.cloud\.google\.com/gce-topology-subblock,HOST:.metadata.labels.cloud\.google\.com/gce-topology-host' | sort -k2,4
Sostituisci NODE_POOL_NAME con il nome del pool di nodi.
Per comprendere la topologia fisica dei nodi GKE nelle VM nell'output, fai riferimento alle seguenti etichette dei nodi:
cloud.google.com/gce-topology-block: l'ID specifico dell'organizzazione del blocco riservato in cui si trova la VM.cloud.google.com/gce-topology-subblock: l'ID specifico dell'organizzazione del sottoblocco in cui si trova la VM.cloud.google.com/gce-topology-host: l'ID dell'host su cui si trova la VM.kubernetes.io/hostname: il nome host del nodo Kubernetes. In genere, questo nome host è anche il nome del nodo GKE.
Più valori di etichetta condividono due VM, più le VM sono fisicamente vicine l'una all'altra. Per ulteriori informazioni su questi termini, consulta Terminologia.
Configura Kueue
Dopo aver installato Kueue, devi configurarlo per specificare l'infrastruttura che gestisce. In genere, Kueue richiede una ClusterQueue definizione della quota di risorse di un'infrastruttura statica o di un'infrastruttura dinamica con la scalabilità automatica del cluster abilitata. ClusterQueue ammette un workload solo se le risorse richieste dal workload sono inferiori o uguali al pool di risorse definito in ClusterQueue. Dopo aver configurato Kueue come descritto in questa sezione, Kueue ammette i workload utilizzando la TAS nel seguente modo:
Carichi di lavoro TAS: Kueue controlla sia la topologia dell'infrastruttura fisica sia il suo utilizzo attuale.
Workload non TAS: Kueue non controlla la topologia dell'infrastruttura fisica. Kueue gestisce l'intera quota definita nella configurazione e lascia l'assegnazione dei nodi a kube-scheduler.
Per capire come fornire una definizione della quota di risorse ClusterQueue a Kueue, esamina i seguenti esempi:
Quota molto elevata: Kueue non interrompe quasi mai l'ammissione di un workload in base alle risorse richieste. In base alle definizioni della TAS, Kueue potrebbe ammettere o meno i workload in base alla topologia dell'infrastruttura. Per ulteriori informazioni, consulta Quota di risorse molto elevata.
Quota realistica: Kueue ammette il workload solo se le risorse richieste dal workload rientrano in questi limiti di quota di risorse. In base alle definizioni della TAS, Kueue controlla la topologia dell'infrastruttura prima di ammettere il workload. Per ulteriori informazioni, consulta Quota di risorse realistica.
Tutti i riferimenti alla quota di risorse nelle sezioni seguenti si riferiscono alla quota di risorse ClusterQueue.
Quota di risorse molto elevata
L'esempio seguente utilizza una quota di risorse molto elevata, in modo che Kueue non interrompa mai un workload in base alla quota di risorse disponibile. Al contrario, Kueue utilizza le informazioni sulla topologia dei nodi disponibili per provare a far corrispondere la topologia ai requisiti del workload.
Per utilizzare la seguente definizione della quota di risorse, completa i seguenti passaggi:
Apri un editor di file a tua scelta. Quindi, includi la seguente definizione della quota in un file YAML denominato
kueue-tas-config-very-high-quota.yaml:apiVersion: kueue.x-k8s.io/v1alpha1 kind: Topology metadata: name: "gke-default" spec: levels: - nodeLabel: "cloud.google.com/gce-topology-block" - nodeLabel: "cloud.google.com/gce-topology-subblock" - nodeLabel: "cloud.google.com/gce-topology-host" - nodeLabel: "kubernetes.io/hostname" --- kind: ResourceFlavor apiVersion: kueue.x-k8s.io/v1beta1 metadata: name: "tas-flavor" spec: nodeLabels: cloud.google.com/gke-nodepool: "NODE_POOL_NAME" topologyName: "gke-default" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: NoSchedule --- apiVersion: kueue.x-k8s.io/v1beta1 kind: ClusterQueue metadata: name: "tas-cluster-queue" spec: namespaceSelector: {} resourceGroups: - coveredResources: ["nvidia.com/gpu"] flavors: - name: "tas-flavor" resources: - name: "nvidia.com/gpu" nominalQuota: 10000000 --- apiVersion: kueue.x-k8s.io/v1beta1 kind: LocalQueue metadata: namespace: "default" name: "tas-user-queue" spec: clusterQueue: "tas-cluster-queue"Sostituisci
NODE_POOL_NAMEcon il nome del pool di nodi.Crea e applica la configurazione della quota di risorse per il sistema di accodamento dei job Kueue:
kubectl create -f kueue-tas-config-very-high-quota.yaml
Quota di risorse realistica
L'esempio precedente ha configurato solo le risorse GPU. Tuttavia, Kueue può gestire tutte le risorse compatibili con Kubernetes.
L'esempio seguente definisce una quota di risorse più realistica, che include CPU, memoria e GPU. Questo vale per 100 macchine a3-ultragpu-8g. Una singola macchina ha 224 vCPU, 2944 GB di memoria e 8 GPU.
Per utilizzare la seguente definizione della quota di risorse, completa i seguenti passaggi:
Apri un editor di file a tua scelta. Quindi, includi la seguente definizione della quota in un file YAML denominato
kueue-tas-config-real-quota.yaml:apiVersion: kueue.x-k8s.io/v1alpha1 kind: Topology metadata: name: "gke-default" spec: levels: - nodeLabel: "cloud.google.com/gce-topology-block" - nodeLabel: "cloud.google.com/gce-topology-subblock" - nodeLabel: "cloud.google.com/gce-topology-host" - nodeLabel: "kubernetes.io/hostname" --- kind: ResourceFlavor apiVersion: kueue.x-k8s.io/v1beta1 metadata: name: "tas-flavor" spec: nodeLabels: cloud.google.com/gke-nodepool: "NODE_POOL_NAME" topologyName: "gke-default" tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: NoSchedule --- apiVersion: kueue.x-k8s.io/v1beta1 kind: ClusterQueue metadata: name: "tas-cluster-queue" spec: namespaceSelector: {} # match all resourceGroups: - coveredResources: ["cpu", "memory", "nvidia.com/gpu"] flavors: - name: "tas-flavor" resources: # numbers below represent quota of 100 a3-ultragpu-8g machines - name: "cpu" nominalQuota: 22400 - name: "memory" nominalQuota: 294400Gi - name: "nvidia.com/gpu" nominalQuota: 800 --- apiVersion: kueue.x-k8s.io/v1beta1 kind: LocalQueue metadata: namespace: "default" name: "tas-user-queue" spec: clusterQueue: "tas-cluster-queue"Sostituisci
NODE_POOL_NAMEcon il nome del pool di nodi.Crea e applica una configurazione della quota di risorse per il sistema di accodamento dei job Kueue:
kubectl create -f kueue-tas-config-real-quota.yamlL'output è simile al seguente:
topology.kueue.x-k8s.io/gke-default created resourceflavor.kueue.x-k8s.io/tas-flavor created clusterqueue.kueue.x-k8s.io/tas-cluster-queue created localqueue.kueue.x-k8s.io/tas-user-queue created
Pianifica i workload con la TAS utilizzando Kueue
I seguenti scenari mostrano come puoi indicare a Kueue e alla TAS di gestire le combinazioni comuni di workload e infrastrutture utilizzando i tipi di richieste di topologia e i livelli di richieste di topologia:
Di seguito sono riportati i tipi di richieste di topologia disponibili (preferiti o obbligatori):
kueue.x-k8s.io/podset-preferred-topology: Kueue assegna la priorità alla pianificazione dell'intero workload all'interno di un determinato livello di topologia, ma ammette comunque un workload che non rientra in questo livello di topologia. Per un workload che potrebbe rientrare in un singolo livello di topologia, Kueue potrebbe pianificare il workload su più istanze di quel livello di topologia.kueue.x-k8s.io/podset-required-topology: Kueue continua a provare ad ammettere questo workload finché l'intero workload non può rientrare nel livello di topologia scelto.
Di seguito sono riportati i livelli di richieste di topologia disponibili, che ti consentono di essere più o meno specifico sull'infrastruttura fisica in cui preferisci o richiedi l'esecuzione del job:
cloud.google.com/gce-topology-blockcloud.google.com/gce-topology-subblockcloud.google.com/gce-topology-hostkubernetes.io/hostname
Per pianificare i workload utilizzando questi valori, utilizza il seguente file YAML del job:
apiVersion: batch/v1
kind: Job
metadata:
generateName: JOB_NAME
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
spec:
parallelism: NUMBER_OF_REPLICAS
completions: NUMBER_OF_REPLICAS
completionMode: Indexed
template:
metadata:
annotations:
ANNOTATIONS_STRING
spec:
containers:
- name: dummy-job
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["60s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
restartPolicy: Never
Sostituisci le seguenti variabili:
JOB_NAME: un nome per il job.NUMBER_OF_REPLICAS: il numero di pod in esecuzione in parallelo.ANNOTATIONS_STRING: consulta la tabella seguente:Tipo e livello di topologia richiesti Descrizione ANNOTATIONS_STRINGPreferito per l'esecuzione all'interno di un nome host (consigliato) Questa configurazione ammetterà il workload purché siano disponibili risorse sufficienti a soddisfare i requisiti di risorse del workload, anche se la capacità è frammentata. Kueue pianificherà i pod nel modo più compatto possibile. kueue.x-k8s.io/podset-preferred-topology: "kubernetes.io/hostname"Obbligatorio per l'esecuzione all'interno di un host Questa configurazione ammetterà il workload se e solo se è disponibile un host con risorse sufficienti a soddisfare i requisiti di risorse del workload.
Questa opzione è utile quando sono presenti più VM per host (ad esempio, tipi di macchine più piccoli) o più pod possono essere eseguiti su un singolo nodo. In questi casi, se il workload viene ammesso, verrà eseguito su un singolo host.
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-host"Preferito per l'esecuzione all'interno di un host Questa configurazione ammetterà il workload purché siano disponibili risorse sufficienti a soddisfare i requisiti di risorse del workload, anche se la capacità è frammentata. Kueue tenterà di pianificare i pod all'interno di un host e utilizzerà host aggiuntivi, se necessario. kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-host"Obbligatorio per l'esecuzione all'interno di un sottoblocco Questa configurazione ammetterà il workload se e solo se è disponibile un sottoblocco con risorse sufficienti a soddisfare i requisiti di risorse del workload. kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-subblock"Preferito per l'esecuzione all'interno di un sottoblocco Questa configurazione ammetterà il workload purché siano disponibili risorse sufficienti a soddisfare i requisiti di risorse del workload, anche se la capacità è frammentata. Kueue tenterà di pianificare i pod all'interno di un sottoblocco e utilizzerà sottoblocchi aggiuntivi, se necessario. In questo caso, Kueue assegnerà un rango più alto a un sottoblocco con una capacità disponibile maggiore, anche se frammentata, rispetto a un sottoblocco con una capacità appena sufficiente a soddisfare i requisiti. kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-subblock"Obbligatorio per l'esecuzione all'interno di un blocco Questa configurazione ammetterà il workload se e solo se le risorse disponibili all'interno di un blocco soddisfano i requisiti di risorse del workload. Se ammesso, Kueue ridurrà al minimo il numero di sottoblocchi e host per pianificare il workload. Ciò potrebbe comportare la frammentazione della capacità disponibile. kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"Preferito per l'esecuzione all'interno di un blocco Questa configurazione ammetterà il workload purché siano disponibili risorse sufficienti a soddisfare i requisiti di risorse del workload, anche se la capacità è frammentata. Kueue tenterà di pianificare i pod all'interno di un blocco e utilizzerà blocchi aggiuntivi, se necessario. kueue.x-k8s.io/podset-preferred-topology: "cloud.google.com/gce-topology-block"
Pianifica i workload utilizzando PodGroup con la TAS utilizzando Kueue
Quando utilizzi PodGroup, devi specificare tre campi aggiuntivi per ogni pod in un PodGroup:
Etichette:
kueue.x-k8s.io/pod-group-name: il nome di un PodGroup utilizzato per l'aggregazione.
kueue.x-k8s.io/pod-group-pod-index: l'indice di ogni singolo pod all'interno del PodGroup.
Annotazioni:
- kueue.x-k8s.io/pod-group-total-count: il conteggio totale dei pod all'interno di un PodGroup.
A seconda del framework ML che utilizzi, un leader di un PodGroup può richiedere o meno una GPU. A causa di una limitazione di Kueue, questi casi devono essere gestiti in modo diverso. Gli esempi seguenti mostrano come creare un PodGroup di tre pod con un leader e due worker.
Caso 1: il leader è anche un worker e richiede una GPU
Se il leader è uno dei worker e richiede anche una GPU, il leader può avere qualsiasi numero all'interno del PodGroup. Per semplicità, nell'esempio seguente l'indice del leader è 0:
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-leader-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
kueue.x-k8s.io/pod-group-pod-index: "0"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
containers:
- name: leader
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-1-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
kueue.x-k8s.io/pod-group-pod-index: "1"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-2-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group"
kueue.x-k8s.io/pod-group-pod-index: "2"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
Caso 2: il leader non è un worker e non richiede una GPU
Se il leader non è uno dei worker a causa della limitazione di Kueue, il leader deve avere l'ultimo indice nel PodGroup, a causa del modo in cui Kueue crea i PodSet. Se il leader non ha l'ultimo indice e il primo worker non utilizza il primo indice, Kueue non applicherà le assegnazioni di rango.
Vedi l'esempio seguente:
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-leader-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
kueue.x-k8s.io/pod-group-pod-index: "2"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
containers:
- name: leader
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
cpu: "1"
limits:
cpu: "1"
restartPolicy: Never
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-0-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
kueue.x-k8s.io/pod-group-pod-index: "0"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
---
apiVersion: v1
kind: Pod
metadata:
generateName: tas-podgroup-worker-1-
labels:
kueue.x-k8s.io/queue-name: tas-user-queue
kueue.x-k8s.io/pod-group-name: "tas-podgroup-example-group2"
kueue.x-k8s.io/pod-group-pod-index: "1"
annotations:
kueue.x-k8s.io/pod-group-total-count: "3"
kueue.x-k8s.io/podset-required-topology: "cloud.google.com/gce-topology-block"
spec:
restartPolicy: Never
containers:
- name: worker
image: gcr.io/k8s-staging-perf-tests/sleep:v0.1.0
args: ["600s"]
resources:
requests:
nvidia.com/gpu: "1"
limits:
nvidia.com/gpu: "1"
Passaggi successivi
Per scoprire di più su come abilitare la previsione dello stato dei nodi nel tuo cluster GKE, consulta Abilita la previsione dello stato dei nodi.
Per scoprire come gestire gli eventi comuni pertinenti ai cluster GKE e ai workload AI, consulta Gestisci i cluster GKE ottimizzati per l'AI.
Per scoprire di più sulla pianificazione dei job su GKE con Kueue, consulta Esegui il deployment di un sistema batch utilizzando Kueue.