Compartir GPUs entre cargas de trabajo con el uso compartido de tiempo de GPU

En esta página se explica cómo permitir que varias cargas de trabajo obtengan acceso de tiempo compartido de GPU a un único acelerador de hardware de GPU de NVIDIA® en los nodos de Google Kubernetes Engine (GKE). Si usas el tiempo compartido de GPU en GKE, puedes usar de forma más eficiente las GPUs conectadas y ahorrar costes de ejecución.

Esta página está dirigida a desarrolladores que diseñan y despliegan cargas de trabajo en clústeres de GKE, así como a administradores y arquitectos que crean y gestionan clústeres de GKE, planifican los requisitos de infraestructura y recursos, y monitorizan el rendimiento de los clústeres. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido, consulta Roles y tareas habituales de los usuarios de GKE. Google Cloud

Antes de leer esta página, asegúrate de que conoces cómo funciona el tiempo compartido en GKE, incluidas las limitaciones y las situaciones en las que debes usar el tiempo compartido de GPU.

Requisitos

  • Versión de GKE: puedes habilitar el tiempo compartido de GPU en clústeres de GKE Standard que ejecuten la versión 1.23.7-gke.1400 de GKE o una posterior. Puedes usar GPUs de tiempo compartido en clústeres de Autopilot de GKE que ejecuten la versión 1.29.3-gke.1093000 de GKE o una posterior.
  • Tipo de GPU: puedes habilitar el tiempo compartido de GPU en todos los modelos de GPU NVIDIA.

Antes de empezar

Antes de empezar, asegúrate de que has realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si quieres usar Google Cloud CLI para esta tarea, instálala y, a continuación, inicialízala. Si ya has instalado la CLI de gcloud, obtén la versión más reciente ejecutando el comando gcloud components update. Es posible que las versiones anteriores de la interfaz de línea de comandos de gcloud no admitan la ejecución de los comandos de este documento.

Habilitar el tiempo compartido de GPU en clústeres y grupos de nodos de GKE

Como administrador de la plataforma, debes habilitar el tiempo compartido de GPU en un clúster Estándar de GKE para que los desarrolladores puedan desplegar cargas de trabajo que usen las GPUs. Para habilitar el tiempo compartido de la GPU, debes hacer lo siguiente:

  1. Habilita el tiempo compartido de GPU en un clúster de GKE.
  2. Instala los controladores de dispositivos de GPU NVIDIA (si es necesario).
  3. Verifica los recursos de GPU disponibles en tus nodos.

Los clústeres de Autopilot que ejecutan la versión 1.29.3-gke.1093000 y posteriores habilitan las GPUs de tiempo compartido de forma predeterminada. El tiempo compartido en los clústeres de Autopilot se configura en la especificación de la carga de trabajo. Para obtener más información, consulta la sección Implementar cargas de trabajo que usen GPUs de tiempo compartido.

Habilitar el tiempo compartido de GPU en un clúster de GKE Standard

Puedes habilitar el tiempo compartido de GPU al crear clústeres estándar de GKE. El grupo de nodos predeterminado del clúster tiene la función habilitada. Sin embargo, debes habilitar el tiempo compartido de GPU cuando crees manualmente nuevos grupos de nodos en ese clúster.

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

Haz los cambios siguientes:

  • CLUSTER_NAME: el nombre del nuevo clúster.
  • CONTROL_PLANE_LOCATION: la ubicación de Compute Engine del plano de control de tu clúster. Proporciona una región para los clústeres regionales o una zona para los clústeres zonales.
  • CLUSTER_VERSION: la versión de GKE del plano de control y los nodos del clúster. Usa la versión 1.23.7-gke.1400 de GKE o una posterior. También puedes especificar un canal de lanzamiento con esa versión de GKE mediante la marca --release-channel=RELEASE_CHANNEL.
  • MACHINE_TYPE: el tipo de máquina de Compute Engine de tus nodos. Te recomendamos que selecciones un tipo de máquina optimizado para aceleradores.
  • GPU_TYPE: el tipo de GPU, que debe ser una plataforma de GPU NVIDIA, como nvidia-tesla-v100.
  • GPU_QUANTITY: número de GPUs físicas que se van a asociar a cada nodo del grupo de nodos predeterminado.
  • CLIENTS_PER_GPU: número máximo de contenedores que pueden compartir cada GPU física.
  • DRIVER_VERSION: la versión del controlador de NVIDIA que se va a instalar. Puede ser uno de los siguientes:
    • default: instala la versión predeterminada del controlador para tu versión de GKE.
    • latest: Instala la versión más reciente del controlador disponible para tu versión de GKE. Solo está disponible para los nodos que usan Container-Optimized OS.
    • disabled: omite la instalación automática de controladores. Debes instalar manualmente un controlador después de crear el grupo de nodos. Si omite gpu-driver-version, esta es la opción predeterminada.

Habilitar el tiempo compartido de GPU en un grupo de nodos de GKE

Puedes habilitar el tiempo compartido de GPU cuando crees manualmente grupos de nodos en un clúster de GKE.

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --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

Haz los cambios siguientes:

  • NODEPOOL_NAME: el nombre del nuevo grupo de nodos.
  • CLUSTER_NAME: el nombre de tu clúster, que debe ejecutar la versión 1.23.7-gke.1400 de GKE o una posterior.
  • CONTROL_PLANE_LOCATION: la ubicación de Compute Engine del plano de control de tu clúster. Proporciona una región para los clústeres regionales o una zona para los clústeres zonales.
  • MACHINE_TYPE: el tipo de máquina de Compute Engine de tus nodos. Te recomendamos que selecciones un tipo de máquina optimizado para aceleradores.
  • GPU_TYPE: el tipo de GPU, que debe ser una plataforma de GPU NVIDIA, como nvidia-tesla-v100.
  • GPU_QUANTITY: número de GPUs físicas que se van a asociar a cada nodo del grupo de nodos.
  • CLIENTS_PER_GPU: número máximo de contenedores que pueden compartir cada GPU física.
  • DRIVER_VERSION: la versión del controlador de NVIDIA que se va a instalar. Se puede definir lo siguiente:

    • default: instala la versión predeterminada del controlador para tu versión de GKE.
    • latest: Instala la versión más reciente del controlador disponible para tu versión de GKE. Solo está disponible para los nodos que usan Container-Optimized OS.
    • disabled: omite la instalación automática de controladores. Debes instalar manualmente un controlador después de crear el grupo de nodos. Si omite gpu-driver-version, esta es la opción predeterminada.

Instalar los controladores de dispositivos de GPU NVIDIA

Antes de continuar, conéctate a tu clúster ejecutando el siguiente comando:

gcloud container clusters get-credentials CLUSTER_NAME

Si has inhabilitado la instalación automática de controladores al crear el clúster o utilizas una versión de GKE anterior a la 1.27.2-gke.1200, debes instalar manualmente un controlador de NVIDIA compatible para gestionar la división de tiempo compartido de las GPUs físicas. Para instalar los controladores, debes implementar un DaemonSet de instalación de GKE que los configure.

Para obtener instrucciones, consulta el artículo Instalar controladores de dispositivos de GPU NVIDIA.

Si tienes previsto usar el aprovisionamiento automático de nodos en tu clúster, también debes configurar el aprovisionamiento automático de nodos con los ámbitos que permitan a GKE instalar los controladores de dispositivos de GPU por ti. Para obtener instrucciones, consulta el artículo Usar el aprovisionamiento automático de nodos con GPUs.

Verificar los recursos de GPU disponibles en los nodos

Para verificar que el número de GPUs visibles en tus nodos coincide con el número que especificaste al habilitar el tiempo compartido de GPU, describe tus nodos:

kubectl describe nodes NODE_NAME

El resultado debería ser similar al siguiente:

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

En este ejemplo de salida, el número de recursos de GPU del nodo es 3 porque el valor especificado para max-shared-clients-per-gpu era 3 y el count de GPUs físicas que se iban a asociar al nodo era 1. Por ejemplo, si el count de las GPUs físicas fuera 2, el resultado mostraría 6 recursos de GPU asignables, tres en cada GPU física.

Desplegar cargas de trabajo que usen el tiempo compartido de la GPU

Como operador de aplicaciones que despliega cargas de trabajo de GPU, puedes seleccionar el tiempo compartido de GPU especificando las etiquetas de nodo adecuadas en un nodeSelector de tus manifiestos. Cuando planifiques tus solicitudes, consulta los límites de solicitudes para asegurarte de que GKE no rechace tus implementaciones.

Para implementar una carga de trabajo que consuma el tiempo compartido de la GPU, sigue estos pasos:

  1. Añade un nodeSelector al manifiesto de tu carga de trabajo para las siguientes etiquetas:

    • cloud.google.com/gke-gpu-sharing-strategy: time-sharing: selecciona los nodos que usan el tiempo compartido de la GPU.
    • cloud.google.com/gke-max-shared-clients-per-gpu: "CLIENTS_PER_GPU": selecciona los nodos que permiten que un número específico de contenedores compartan la GPU subyacente.
  2. Añade la solicitud de recursos de nvidia.com/gpu=1GPU a la especificación de tu contenedor, en spec.containers.resources.limits.

Por ejemplo, en los siguientes pasos se muestra cómo desplegar tres pods en un grupo de nodos de tiempo compartido de GPU. GKE asigna cada contenedor a la misma GPU física. Los contenedores imprimen el UUID de la GPU que está conectada a ese contenedor.

  1. Guarda el siguiente archivo de manifiesto 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
      

Haz los cambios siguientes:

  • GPU_TYPE: el tipo de GPU.
  • CLIENTS_PER_GPU: el número de cargas de trabajo que usarán esta GPU. En este ejemplo, usa 3.
  • GPU_COUNT: número de GPUs físicas que se van a asociar al nodo. En este ejemplo, usa 1.

Estándar

        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
      

Haz los cambios siguientes:

  • SHARING_STRATEGY con "time-sharing" para solicitar tiempo compartido para tu GPU.
  • CLIENTS_PER_GPU: el número de cargas de trabajo que usarán esta GPU. En este ejemplo, usa 3.
  1. Aplica el archivo de manifiesto:

    kubectl apply -f gpu-timeshare.yaml
    
  2. Comprueba que todos los pods se estén ejecutando:

    kubectl get pods -l=app=cuda-simple
    
  3. Consulta los registros de cualquier pod para ver el UUID de la GPU:

    kubectl logs POD_NAME
    

    El resultado debería ser similar al siguiente:

    GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-0771302b-eb3a-6756-7a23-0adcae8efd47)
    
  4. Si tus nodos tienen una GPU física conectada, consulta los registros de cualquier otro pod del mismo nodo para verificar que el UUID de la GPU sea el mismo:

    kubectl logs POD2_NAME
    

    El resultado debería ser similar al siguiente:

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

Usar el tiempo compartido de GPU con GPUs de varias instancias

Como administrador de la plataforma, puede que quieras combinar varias funciones de GPU de GKE. El tiempo compartido de la GPU funciona con GPUs de varias instancias, que dividen una sola GPU física en hasta siete partes. Estas particiones están aisladas entre sí. Puedes configurar el tiempo compartido de GPU para cada partición de GPU multiinstancia.

Por ejemplo, si asignas el valor gpu-partition-size a 1g.5gb, la GPU subyacente se dividirá en siete particiones. Si también asignas el valor max-shared-clients-per-gpu a 3, cada partición admitirá hasta tres contenedores, lo que supone un total de hasta 21 dispositivos de uso compartido de GPU disponibles para asignar en esa GPU física. Para obtener información sobre cómo se gpu-partition-size convierte en particiones reales, consulta Particiones de GPU de varias instancias.

Para crear un clúster de GPUs con varias instancias y con el tiempo compartido de GPU habilitado, ejecuta el siguiente comando:

Autopilot

Con Autopilot, se pueden usar las GPUs de tiempo compartido y las GPUs con varias instancias juntas usando ambos conjuntos de selectores de nodos.

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

Estándar

Con Estándar, debes crear un clúster de varias instancias con tiempo compartido de GPU ejecutando el siguiente comando:

gcloud container node-pools create NODEPOOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=CONTROL_PLANE_LOCATION \
    --machine-type=MACHINE_TYPE \
    --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

Sustituye PARTITION_SIZE por el tamaño de la partición de GPU con varias instancias que quieras, como 1g.5gb.

Limitaciones

  • Con el tiempo compartido de la GPU, GKE aplica el aislamiento del espacio de direcciones, el aislamiento del rendimiento y el aislamiento de errores entre los contenedores que comparten una GPU física. Sin embargo, los límites de memoria no se aplican a las GPUs. Para evitar problemas de falta de memoria, define límites de memoria de GPU en tus cargas de trabajo. Para evitar problemas de seguridad, solo implementa cargas de trabajo que estén en el mismo límite de confianza para compartir el tiempo de la GPU.
  • Para evitar comportamientos inesperados durante la asignación de capacidad, GKE puede rechazar determinadas solicitudes de tiempo compartido de GPU. Para obtener más información, consulta Solicitudes de GPU para compartir el tiempo de GPU.
  • El número máximo de contenedores que pueden usar el tiempo compartido en una sola GPU física es 48. Cuando planifiques la configuración de tiempo compartido de la GPU, ten en cuenta las necesidades de recursos de tus cargas de trabajo y la capacidad de las GPUs físicas subyacentes para optimizar el rendimiento y la capacidad de respuesta.

Siguientes pasos