Partager des GPU avec plusieurs charges de travail à l'aide de NVIDIA MPS


Cette page explique comment utiliser le service multi-processus (MPS) de CUDA pour permettre à plusieurs charges de travail de partager un même accélérateur matériel de GPU NVIDIA dans vos nœuds Google Kubernetes Engine (GKE).

Présentation

NVIDIA MPS est une solution de partage de GPU qui permet à plusieurs conteneurs de partager un même matériel GPU NVIDIA physique associé à un nœud.

NVIDIA MPS s'appuie sur le service multi-processus de NVIDIA sur CUDA. NVIDIA MPS est une autre mise en œuvre de l'API CUDA compatible binaire, conçue pour permettre aux applications CUDA coopératives multiprocessus de s'exécuter simultanément sur un seul appareil GPU de manière transparente.

Avec NVIDIA MPS, vous pouvez spécifier le nombre maximal de conteneurs partagés d'un GPU physique. Cette valeur détermine la quantité de puissance de GPU physique obtenue par chaque conteneur, en fonction des caractéristiques suivantes:

Pour en savoir plus sur la planification des GPU avec NVIDIA MPS, lorsque vous devez utiliser CUDA MPS, consultez la page À propos des solutions de partage de GPU dans GKE.

À qui ce guide est-il destiné ?

Les instructions de cette rubrique s'appliquent à vous si vous remplissez l'un des rôles suivants :

  • Administrateur de plate-forme : crée et gère un cluster GKE, planifie les exigences d'infrastructure et de ressources, et surveille les performances du cluster.
  • Développeur d'applications : conçoit et déploie des charges de travail sur des clusters GKE. Si vous souhaitez obtenir des instructions pour demander des MPS NVIDIA avec des GPU, consultez la page Déployer des charges de travail qui utilisent NVIDIA MPS avec des GPU.

Conditions requises

  • Version de GKE: vous pouvez activer le partage de GPU avec NVIDIA MPS sur les clusters GKE Standard exécutant GKE version 1.27.7-gke.1088000 ou ultérieure.
  • Type de GPU: vous pouvez activer NVIDIA MPS pour tous les types de GPU NVIDIA Tesla®.

Avant de commencer

Avant de commencer, effectuez les tâches suivantes :

  • Activez l'API Google Kubernetes Engine.
  • Activer l'API Google Kubernetes Engine
  • Si vous souhaitez utiliser Google Cloud CLI pour cette tâche, installez puis initialisez gcloud CLI. Si vous avez déjà installé gcloud CLI, assurez-vous de disposer de la dernière version en exécutant la commande gcloud components update.

Activer NVIDIA MPS avec des GPU sur des clusters GKE

En tant qu'administrateur de plate-forme, vous devez activer NVIDIA MPS avec des GPU sur un cluster GKE Standard. Les développeurs d'applications peuvent ensuite déployer des charges de travail pour utiliser les MPS NVIDIA avec des GPU. Pour activer NVIDIA MPS avec des GPU sur GKE, procédez comme suit:

  1. Activez NVIDIA MPS avec les GPU sur un nouveau cluster GKE.
  2. Installez les pilotes d'appareils GPU NVIDIA (si nécessaire).
  3. Vérifiez les ressources GPU disponibles sur vos nœuds.

Activer NVIDIA MPS avec des GPU sur un cluster GKE

Vous pouvez activer NVIDIA MPS avec des GPU lorsque vous créez des clusters GKE Standard. La fonctionnalité est activée sur le pool de nœuds par défaut du cluster. Vous devez toujours activer NVIDIA MPS avec des GPU lorsque vous créez manuellement de nouveaux pools de nœuds dans ce cluster.

Créez un cluster avec NVIDIA MPS activé à l'aide de Google Cloud CLI:

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=mps,max-shared-clients-per-gpu=CLIENTS_PER_GPU,gpu-driver-version=DRIVER_VERSION

Remplacez les éléments suivants :

  • CLUSTER_NAME : nom de votre nouveau cluster
  • COMPUTE_REGION : région Compute Engine du nouveau cluster. Pour les clusters zonaux, spécifiez --zone=COMPUTE_ZONE. Le type de GPU que vous utilisez doit être disponible dans la zone sélectionnée.
  • CLUSTER_VERSION : version de GKE pour le plan de contrôle et les nœuds du cluster. Utilisez GKE version 1.27.7-gke.1088000 ou ultérieure. Vous pouvez également spécifier une version disponible avec cette version de GKE à l'aide de l'option --release-channel=RELEASE_CHANNEL.
  • MACHINE_TYPE : type de machine Compute Engine pour vos nœuds.
  • GPU_TYPE : type de GPU, qui doit être une plate-forme de GPU NVIDIA Tesla, telle que nvidia-tesla-v100.
  • GPU_QUANTITY : nombre de GPU physiques à associer à chaque nœud du pool de nœuds par défaut.
  • CLIENTS_PER_GPU : nombre maximal de conteneurs pouvant partager chaque GPU physique.
  • DRIVER_VERSION : version du pilote NVIDIA à installer. La valeur peut être l'une des suivantes :
    • default : installe la version de pilote par défaut pour votre version de GKE.
    • latest : installe la dernière version de pilote disponible pour votre version de GKE. Disponible seulement pour les nœuds qui utilisent Container-Optimized OS.
    • disabled : passe l'installation automatique du pilote. Vous devez installer manuellement un pilote après avoir créé le pool de nœuds. Si vous omettez la commande gpu-driver-version, cette option est celle configurée par défaut.

Activer NVIDIA MPS avec des GPU sur un nouveau pool de nœuds

Vous pouvez activer NVIDIA MPS avec des GPU lorsque vous créez manuellement de nouveaux pools de nœuds dans un cluster GKE. Créez un pool de nœuds avec NVIDIA MPS activé à l'aide de Google Cloud CLI:

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=mps,max-shared-clients-per-gpu=CONTAINER_PER_GPU,gpu-driver-version=DRIVER_VERSION

Remplacez les éléments suivants :

  • NODEPOOL_NAME : nom de votre nouveau pool de nœuds.
  • CLUSTER_NAME : nom de votre cluster, qui doit exécuter GKE version 1.27.7-gke.1088000 ou ultérieure.
  • COMPUTE_REGION : région Compute Engine du cluster. Pour les clusters zonaux, spécifiez --zone=COMPUTE_ZONE.
  • MACHINE_TYPE : type de machine Compute Engine pour vos nœuds. Pour les GPU  A100, utilisez un type de machine A2. Pour tous les autres GPU, utilisez un type de machine N1.
  • GPU_TYPE : type de GPU, qui doit être une plate-forme de GPU NVIDIA Tesla, telle que nvidia-tesla-v100.
  • GPU_QUANTITY : nombre de GPU physiques à associer à chaque nœud du pool de nœuds.
  • CONTAINER_PER_GPU : nombre maximal de conteneurs pouvant partager chaque GPU physique.
  • DRIVER_VERSION : version du pilote NVIDIA à installer. Les possibilités suivantes s'offrent à vous :

    • default : installe la version de pilote par défaut pour votre version de GKE.
    • latest : installe la dernière version de pilote disponible pour votre version de GKE. Disponible seulement pour les nœuds qui utilisent Container-Optimized OS.
    • disabled : passe l'installation automatique du pilote. Vous devez installer manuellement un pilote après avoir créé le pool de nœuds. Si vous omettez la commande gpu-driver-version, cette option est celle configurée par défaut.

Installer des pilotes d'appareils GPU NVIDIA

Si vous avez choisi de désactiver l'installation automatique des pilotes lors de la création du cluster, ou si vous utilisez une version de GKE antérieure à la version 1.27.2-gke.1200, vous devez installer manuellement un pilote NVIDIA compatible pour gérer la division NVIDIA MPS des GPU physiques. Pour installer les pilotes, vous devez déployer un DaemonSet d'installation de GKE qui configure les pilotes.

Pour obtenir des instructions, consultez la page Installer des pilotes d'appareils GPU NVIDIA.

Vérifier les ressources GPU disponibles

Vous pouvez vérifier que le nombre de GPU dans vos nœuds correspond au nombre que vous avez spécifié lors de l'activation de NVIDIA MPS. Vous pouvez également vérifier que le daemon de contrôle NVIDIA MPS est en cours d'exécution.

Vérifier les ressources GPU disponibles sur vos nœuds

Pour vérifier les ressources GPU disponibles sur vos nœuds, exécutez la commande suivante:

kubectl describe nodes NODE_NAME

Remplacez NODE_NAME par le nom de l'un de vos nœuds.

Le résultat ressemble à ce qui suit :

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

Dans ce résultat, le nombre de ressources GPU sur le nœud est 3 en raison des valeurs suivantes:

  • La valeur de max-shared-clients-per-gpu est 3.
  • La valeur count des GPU physiques à associer au nœud est 1. Si la valeur count des GPU physiques était 2, le résultat afficherait 6 ressources GPU pouvant être allouées, trois sur chaque GPU physique.

Vérifier que le daemon de contrôle MPS est en cours d'exécution

Le plug-in d'appareils GPU effectue une vérification de l'état sur le daemon de contrôle MPS. Lorsque le daemon de contrôle MPS est opérationnel, vous pouvez déployer un conteneur.

Pour vérifier que le MPS est dans l'état, exécutez la commande suivante:

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

Le résultat ressemble à ce qui suit :

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
...

Dans le résultat, vous pouvez constater que les événements suivants se sont produits:

  • L'erreur failed to start GPU device manager précède l'erreur MPS is healthy. Cette erreur est temporaire. Si le message MPS is healthy s'affiche, le daemon de contrôle est en cours d'exécution.
  • Le message active thread percentage = 100.0 signifie que l'ensemble de la ressource GPU physique possède un thread complètement actif.

Déployer des charges de travail qui utilisent MPS

En tant qu'opérateur d'application qui déploie des charges de travail GPU, vous pouvez indiquer à GKE de partager des unités de partage MPS dans le même GPU physique. Dans le fichier manifeste suivant, vous demandez un GPU physique et définissez max-shared-clients-per-gpu=3. Le GPU physique obtient trois unités de partage MPS et démarre une tâche nvidia/samples:nbody avec trois pods (conteneurs) exécutés en parallèle.

  1. Enregistrez le manifeste sous le nom gpu-mps.yaml :

      apiVersion: batch/v1
      kind: Job
      metadata:
        name: nbody-sample
      spec:
        completions: 3
        parallelism: 3
        template:
          spec:
            hostIPC: true
            nodeSelector:
              cloud.go888ogle.com.fqhub.com/gke-gpu-sharing-strategy: mps
            containers:
              - name: nbody-sample
                image: nvidia/samples:nbody
                command: ["/tmp/nbody"]
                args: ["-benchmark", "-i=5000"]
                resources:
                  limits:
                    nvidia.com/gpu: 1
            restartPolicy: "Never"
        backoffLimit: 1
    

    Dans le fichier manifeste :

    • hostIPC: true permet aux pods de communiquer avec le daemon de contrôle MPS. Veuillez renseigner ce champ. Cependant, gardez à l'esprit que la configuration hostIPC: true permet au conteneur d'accéder à la ressource hôte, ce qui présente des risques pour la sécurité.
    • 5 000 itérations s'exécutent en mode benchmark.
  2. Appliquez le fichier manifeste :

    kubectl apply -f gpu-mps.yaml
    
  3. Vérifiez que tous les pods sont en cours d'exécution:

    kubectl get pods
    

    Le résultat ressemble à ce qui suit :

    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. Consultez les journaux des pods pour vérifier que la tâche est terminée:

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

    Le résultat ressemble à ce qui suit :

    ...
    > 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
    ...
    

    Étant donné que GKE exécute 50 000 itérations, le journal peut prendre plusieurs minutes.

Effectuer un nettoyage

Supprimez la tâche et tous ses pods en exécutant la commande suivante:

kubectl delete job --all

Limiter la mémoire de l'appareil épinglée et le thread actif avec NVIDIA MPS

Par défaut, lorsque vous utilisez un GPU avec NVIDIA MPS sur GKE, les variables d'environnement CUDA suivantes sont injectées dans la charge de travail GPU:

  • CUDA_MPS_ACTIVE_THREAD_PERCENTAGE: cette variable indique le pourcentage de threads disponibles que chaque unité de partage MPS peut utiliser. Par défaut, chaque unité de partage MPS du GPU est définie sur 100 / MaxSharedClientsPerGPU pour obtenir une tranche égale de calcul GPU en termes de multiprocesseur de flux.
  • CUDA_MPS_PINNED_DEVICE_MEM_LIMIT: cette variable limite la quantité de mémoire GPU pouvant être allouée par une unité de partage MPS de GPU. Par défaut, chaque unité de partage MPS du GPU est définie sur total mem / MaxSharedClientsPerGPU pour obtenir une tranche égale de la mémoire GPU.

Pour définir une limite de ressources pour vos charges de travail GPU, configurez les variables d'environnement NVIDIA MPS suivantes:

  1. Examinez et créez l'image de l'exemple cuda-mps dans GitHub.

  2. Enregistrez le manifeste suivant sous le nom cuda-mem-and-sm-count.yaml :

    apiVersion: v1
    kind: Pod
    metadata:
      name: cuda-mem-and-sm-count
    spec:
      hostIPC: true
      nodeSelector:
        cloud.go888ogle.com.fqhub.com/gke-gpu-sharing-strategy: mps
      containers:
        - name: CUDA_MPS_IMAGE
          image: gcr.io/gracegao-gke-dev/cuda-mem-and-sm-count:latest
          securityContext:
            privileged: true
          resources:
            limits:
              nvidia.com/gpu: 1
    

    Remplacez CUDA_MPS_IMAGE par le nom de l'image que vous avez créée pour l'exemple cuda-mps.

    NVIDIA MPS nécessite de définir hostIPC:true sur les pods. La configuration hostIPC:true permet au conteneur d'accéder à la ressource hôte, ce qui présente des risques de sécurité.

  3. Appliquez le fichier manifeste :

    kubectl apply -f cuda-mem-and-sm-count.yaml
    
  4. Vérifiez les journaux de ce pod:

    kubectl logs cuda-mem-and-sm-count
    

    Dans un exemple utilisant NVIDIA Tesla® L4 avec gpu-sharing-strategy=mps et max-shared-clients-per-gpu=3, le résultat ressemble à ce qui suit:

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

    Dans cet exemple, le GPU NVIDIA Tesla® L4 dispose de 60 SM et de 24 Go de mémoire. Chaque unité de partage MPS dispose d'environ 33% de threads actifs et de 8 Go de mémoire.

  5. Mettez à jour le fichier manifeste pour demander 2 nvidia.com/gpu:

      resources:
            limits:
              nvidia.com/gpu: 2
    

    Le résultat ressemble à ce qui suit :

    For device 0:  Free memory: 15230 M, Total memory: 22491 M
    For device 0:  multiProcessorCount: 38
    
  6. Mettez à jour le fichier manifeste pour remplacer les variables CUDA_MPS_ACTIVE_THREAD_PERCENTAGE et 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"
    

    Le résultat ressemble à ce qui suit :

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

Limites

  • Le MPS sur les GPU antérieurs à Volta (k80 et P100) présente des fonctionnalités limitées par rapport aux types de GPU dans et après Volta.
  • Avec NVIDIA MPS, GKE s'assure que chaque conteneur dispose d'une mémoire d'appareil épinglée et de threads actifs limités. Cependant, les autres ressources telles que la bande passante mémoire, les encodeurs ou les décodeurs ne sont pas capturées dans le cadre de ces limites de ressources. Par conséquent, les conteneurs peuvent avoir un impact négatif sur les performances des autres conteneurs s'ils demandent tous la même ressource illimitée.
  • NVIDIA MPS dispose de limites de protection de la mémoire et de limitation des erreurs. Nous vous recommandons d'évaluer ces limites pour vous assurer de la compatibilité avec vos charges de travail.
  • NVIDIA MPS nécessite de définir hostIPC:true sur les pods. La configuration hostIPC:true permet au conteneur d'accéder à la ressource hôte, ce qui présente des risques de sécurité.
  • GKE peut rejeter certaines requêtes de GPU lors de l'utilisation de NVIDIA MPS, afin d'éviter tout comportement inattendu lors de l'allocation de capacité. Pour en savoir plus, consultez la section Limites de requêtes pour les solutions de partage de GPU.
  • Le nombre maximal de conteneurs pouvant partager un seul GPU physique avec NVIDIA MPS est de 48 (les GPU pré-Volta n'acceptent que 16). Lorsque vous planifiez votre configuration NVIDIA MPS, tenez compte des besoins en ressources de vos charges de travail et de la capacité des GPU physiques sous-jacents afin d'optimiser vos performances et votre réactivité.
  • La configuration de l'API NVIDIA MPS n'est possible qu'avec Google Cloud CLI ou la console Google Cloud.

Étapes suivantes