View a markdown version of this page

Uso de la segmentación temporal con GPU de NVIDIA en Amazon EKS - Amazon EKS

Ayude a mejorar esta página

Para contribuir a esta guía del usuario, elija el enlace Edit this page on GitHub que se encuentra en el panel derecho de cada página.

Uso de la segmentación temporal con GPU de NVIDIA en Amazon EKS

La segmentación temporal permite que varios pods compartan una sola GPU de NVIDIA física. El programador de Kubernetes coloca varios pods en la misma GPU y el programador de CUDA de la GPU multiplexa en el tiempo el trabajo. La segmentación temporal es la estrategia más sencilla para compartir la GPU. Utiliza solo software, no requiere hardware especial y funciona en todos los tipos de instancias de GPU de NVIDIA en AWS. La segmentación temporal no aísla la memoria ni la computación entre los pods que comparten una GPU. Funciona mejor para cargas de trabajo que utilizan poco la GPU, como los servicios de inferencia que están inactivos entre solicitudes o los entornos de desarrollo en los que varios usuarios comparten una GPU. Para las cargas de trabajo que requieren aislamiento de memoria y computación por hardware, utilice GPU de varias instancias (MIG) en su lugar.

En Amazon EKS, puede administrar la segmentación temporal con el controlador de DRA de NVIDIA o el complemento para dispositivos de NVIDIA.

La segmentación temporal solo se puede utilizar con Karpenter si se utiliza el aprovisionamiento de capacidad estático. La segmentación temporal no está disponible actualmente en el modo automático de EKS.

La segmentación temporal es una buena opción cuando:

  • El uso de la GPU es constantemente bajo, por ejemplo, los servicios de inferencia sensibles a la latencia que están inactivos entre solicitudes.

  • Varios desarrolladores comparten un único nodo de GPU para llevar a cabo tareas de desarrollo o de trabajo con cuadernos.

  • Los nodos utilizan un tipo de instancia de GPU que no admite MIG, como las familias g5, g6 o g6e.

  • Puede aceptar que un pod sea a veces más lento porque otro pod de la misma GPU esté ocupado.

Considere la posibilidad de adoptar otro enfoque cuando:

  • Necesite aislar la memoria. Los pods de una GPU con intervalos de tiempo compartido comparten la misma memoria que la GPU y un pod puede agotar la memoria de la que dependen otros pods. Use MIG para aislar la memoria.

  • Necesite una latencia predecible por pod o una calidad de servicio. El programador de GPU comparte la computación entre ranuras en la medida en que sea posible y sin garantías.

  • Ejecute cargas de trabajo de entrenamiento. La segmentación temporal agrega un cambio de contexto que reduce la eficiencia del entrenamiento. Un trabajo con punto de control que otro pod ralentiza debe volver a intentarlo desde el último punto de control.

Consideraciones

Revise las siguientes consideraciones antes de usar la segmentación temporal en producción.

Consideraciones generales

  • Sin aislamiento de memoria: los pods que comparten una GPU con segmentación temporal comparten su memoria. Un pod puede asignar memoria que otros pods necesitan, lo que puede producir errores de memoria insuficiente. Haga coincidir la cantidad de pods que comparten cada GPU con el consumo de memoria de las cargas de trabajo. Si los pods cargan modelos grandes de forma habitual, comparta menos pods por GPU o use MIG.

  • Uso compartido de computación al máximo esfuerzo: el programador de GPU comparte la computación entre los pods al máximo esfuerzo posible y no garantiza ninguna computación proporcional a cada pod.

  • La segmentación temporal y MPS no pueden compartir la misma GPU: la segmentación temporal establece el modo de computación de la GPU en DEFAULT, mientras que el servicio multiproceso (MPS) de NVIDIA requiere EXCLUSIVE_PROCESS. Puede usar ambas estrategias en el mismo clúster, pero no en la misma GPU física al mismo tiempo. La segmentación temporal tampoco tiene ningún efecto en una instancia de MIG. Para compartir una única instancia de MIG entre contenedores, utilice MPS en su lugar.

  • Métricas por contenedor: el administrador de GPU para centros de datos de NVIDIA (DCGM) no puede atribuir métricas a contenedores individuales cuando la segmentación temporal está activa. Las métricas de la GPU siguen disponibles, pero no puede identificar qué pod consumió una cantidad determinada de recursos de la GPU.

Consideraciones sobre el controlador de DRA de NVIDIA

  • Característica alfa: la segmentación temporal mediante el controlador de DRA requiere la puerta de características TimeSlicingSettings, que es una característica alfa deshabilitada de forma predeterminada. Para obtener más información, consulte Uso de la segmentación temporal de la GPU con el controlador de DRA de NVIDIA.

  • Solo uso compartido mediado por el usuario: los pods solo comparten una GPU cuando hacen referencia a la misma ResourceClaim o ResourceClaimTemplate, lo cual depende del espacio de nombres, por lo que el uso compartido no puede cruzar espacios de nombres. El uso compartido mediado por el sistema es una capacidad futura propuesta.

  • Deshabilite el complemento para dispositivos integrado en Bottlerocket: el controlador de DRA no se puede ejecutar junto con el complemento para dispositivos de NVIDIA en el mismo nodo. En Bottlerocket, deshabilite el complemento para dispositivos integrado, que requiere la versión 1.63.0 o posterior de Bottlerocket. Para obtener más información, consulte Instalación del controlador de DRA de NVIDIA.

  • Compatibilidad con la computación: el controlador de DRA de NVIDIA es compatible con el aprovisionamiento de capacidad estática en Karpenter, los grupos de nodos administrados de EKS o los nodos autoadministrados, pero no es compatible con el modo automático de EKS. Para obtener más información, consulte la documentación de NodePool estática de Karpenter en el sitio web de Karpenter.

Consideraciones sobre el complemento para dispositivos de NVIDIA

  • Uso compartido de computación al máximo con ranuras: el complemento para dispositivos anuncia un número fijo de ranuras por GPU. Si un solo pod solicita más de una ranura, no recibe computación adicional. Habilite la opción fail-requests-greater-than-one para rechazar los pods que soliciten más de una ranura.

  • Aprovisionamiento con Karpenter: Karpenter considera cada solicitud nvidia.com/gpu como una GPU física, incluso cuando la GPU tiene habilitada la segmentación temporal. Para obtener más información, consulte el problema 2140 de Karpenter en GitHub.

  • No es compatible con el modo automático de EKS: el modo automático de EKS administra el complemento para dispositivos de NVIDIA y no expone su configuración. Como la segmentación temporal requiere la configuración del complemento para dispositivos, no se puede aplicar una configuración de segmentación temporal en los nodos del modo automático de EKS.

  • Cambios en la configuración de la segmentación temporal: el complemento para dispositivos de NVIDIA no supervisa el ConfigMap de la segmentación temporal para detectar cambios. Reinicie el complemento para dispositivos después de actualizar la configuración.

Opciones de configuración

Puede utilizar la segmentación temporal para las GPU de NVIDIA con las AMI de NVIDIA de AL2023 y Bottlerocket optimizadas para EKS. La configuración de la segmentación temporal varía en función de si se utiliza el controlador de DRA de NVIDIA o el complemento para dispositivos de NVIDIA.

NVIDIA DRA driver

Las AMI aceleradas optimizadas para EKS no incluyen el controlador de DRA de NVIDIA. Si utiliza Bottlerocket, debe deshabilitar el complemento para dispositivos NVIDIA integrado antes de utilizar el controlador de DRA de NVIDIA mediante el establecimiento de settings.kubelet-device-plugins.nvidia.enabled = false en los datos de usuario del nodo, lo que requiere la versión 1.63.0 o posterior de Bottlerocket. Para obtener más información, consulte Instalación del controlador de DRA de NVIDIA.

Con el controlador de DRA de NVIDIA, la segmentación temporal se configura mediante ResourceClaimTemplates. El campo interval controla la duración de la segmentación temporal de CUDA.

Interval Descripción

Valor predeterminado

Utiliza el intervalo predeterminado integrado en el controlador de GPU de NVIDIA

Short

Intervalo más corto, los contextos cambian con más frecuencia

Medio

Intervalo intermedio

Largo

cada contexto dura más tiempo por turno antes que se asuma la prioridad

NVIDIA device plugin
  • Bottlerocket: la AMI incluye un complemento para dispositivos de NVIDIA preinstalado. La segmentación temporal se puede configurar a través de los ajustes de Bottlerocket, sin instalar el complemento para dispositivos, un gráfico de Helm ni ConfigMap.

  • AL2023: instale el complemento para dispositivos de NVIDIA tal y como se describe en Instalación del complemento para dispositivos de Kubernetes de NVIDIA y proporcione la configuración de segmentación temporal a través de ConfigMap.

    Las siguientes opciones controlan la forma en que el complemento para dispositivos de NVIDIA anuncia y administra las GPU con segmentación temporal. Los nombres de los campos difieren entre la configuración de Bottlerocket y el ConfigMap de AL2023, como se muestra en los procedimientos siguientes.

    Opción Valor recomendado Descripción

    Réplicas

    Entre 2 y 8

    El número de ranuras programables que se pueden anunciar por GPU física. Los valores más altos permiten compartir más, pero aumentan la contención entre pods.

    Cambio de nombre de forma predeterminada

    false

    Si es false, los pods solicitan nvidia.com/gpu, lo que mantiene la compatibilidad con los manifiestos existentes. Si es true, el complemento para dispositivos anuncia el recurso como nvidia.com/gpu.shared, y los pods deben solicitar ese nombre. Configúrelo en true cuando ejecute grupos de nodos de GPU compartidos y dedicados y desee que las cargas de trabajo seleccionen el recurso compartido de forma explícita.

    Cantidad de solicitudes con error superior a uno

    true

    Rechaza los pods que solicitan más de una ranura de segmentación temporal. Un pod que solicita más de una ranura no recibe computación proporcional. Habilite esta configuración para evitar una configuración incorrecta habitual.

    Para ver la lista completa de las opciones de uso compartido de GPU y sus valores predeterminados, consulta la documentación del complemento para dispositivos de NVIDIA de Kubernetes en GitHub.

Uso de la segmentación temporal de la GPU con el controlador de DRA de NVIDIA

Con el controlador de DRA de NVIDIA, los pods comparten una GPU al hacer referencia a una ResourceClaim común que solicita la DeviceClass gpu.nvidia.com con una segmentación temporal GpuConfig.

El controlador de DRA de NVIDIA implementa actualmente la segmentación temporal mediada por el usuario: una GPU solo se comparte entre los pods y los contenedores a los que se haga referencia de forma explícita en la misma instrucción. Como ResourceClaim y ResourceClaimTemplate dependen del espacio de nombres, los pods que comparten una GPU de este modo deben estar en el mismo espacio de nombres. Para compartir una GPU entre los contenedores de un solo pod, cada contenedor debe hacer referencia al mismo nombre de solicitud en la instrucción. Los contenedores que hacen referencia a diferentes nombres de solicitudes reciben cada uno una GPU independiente. Cree una ResourceClaimTemplate independiente para cada intervalo de segmentación temporal que necesite y una para cada espacio de nombres en el que desee compartir las GPU.

La segmentación temporal mediada por el sistema es aquella en la que el controlador comparte una GPU entre instrucciones independientes (incluso entre espacios de nombres) y se basa en criterios definidos por el sistema y no en una instrucción que configure el usuario. Para obtener más información sobre la segmentación temporal mediada por el sistema, consulte la segmentación temporal de GPU mediada por el sistema (problema n.º 659) y la solicitud de extracción n.º 1257 en GitHub.

importante

La segmentación temporal mediante el controlador de DRA requiere la puerta de características TimeSlicingSettings, que es una característica alfa deshabilitada de forma predeterminada. Si solicita la estrategia de uso compartido TimeSlicing sin activar esta puerta de características, el controlador no preparará el dispositivo y el pod se quedará en ContainerCreating con un evento FailedPrepareDynamicResources que notifica error validating GPU config: unknown GPU sharing strategy: TimeSlicing. Habilite la puerta de características solo si acepta los riesgos de usar una capacidad alfa.

Requisitos previos

  • Un clúster de Amazon EKS que ejecuta la versión 1.34 de Kubernetes o una posterior. El controlador de DRA de NVIDIA es compatible con el aprovisionamiento de capacidad estática en Karpenter, los grupos de nodos administrados de EKS o los nodos autoadministrados.

  • Nodos con tipos de instancia de GPU NVIDIA con la AMI de NVIDIA de AL2023 optimizada para EKS.

  • El controlador de DRA de NVIDIA se ha instalado como se describe en Instalación del controlador de DRA de NVIDIA, con la puerta de características TimeSlicingSettings habilitada.

Procedimiento

  1. Cree una ResourceClaim que solicite una GPU con la estrategia de uso compartido TimeSlicing. Varios pods que hacen referencia a esta instrucción comparten la misma GPU física.

    cat <<EOF | kubectl apply -f - apiVersion: resource.k8s.io/v1 kind: ResourceClaim metadata: name: shared-timeslice-gpu spec: devices: requests: - name: gpu exactly: deviceClassName: gpu.nvidia.com count: 1 config: - requests: ["gpu"] opaque: driver: gpu.nvidia.com parameters: apiVersion: resource.nvidia.com/v1beta1 kind: GpuConfig sharing: strategy: TimeSlicing timeSlicingConfig: interval: Long EOF
  2. Implemente dos o más pods que hagan referencia a la ResourceClaim compartida por el nombre. Cada pod hace referencia a la instrucción mediante resourceClaims y resources.claims.

    cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: share-a spec: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule containers: - name: cuda image: nvidia/cuda:12.6.0-base-ubuntu22.04 command: ["nvidia-smi", "-L"] resources: claims: - name: gpu resourceClaims: - name: gpu resourceClaimName: shared-timeslice-gpu restartPolicy: OnFailure EOF
  3. Verifique que los pods compartan la misma GPU física. Ejecute nvidia-smi -L en cada pod y confirme que muestren el mismo UUID de GPU.

    kubectl logs share-a

    Un ejemplo de salida sería el siguiente. Un segundo pod que haga referencia a la misma instrucción informa de un UUID de GPU idéntico, lo que confirma que ambos pods comparten una GPU física.

    GPU 0: NVIDIA L4 (UUID: GPU-b41973ee-5d0a-cde8-6287-12b53f861f02)

Utilice la segmentación temporal de GPU en los nodos de Bottlerocket con el complemento para dispositivos de NVIDIA

En Bottlerocket, la AMI acelerada optimizada para EKS incluye el complemento para dispositivos de NVIDIA. Habilite la segmentación temporal a través de la configuración settings.kubelet-device-plugins.nvidia, que Bottlerocket convierte en la configuración del complemento para dispositivos cuando se inicia el nodo.

Requisitos previos

  • Un clúster de Amazon EKS. El siguiente procedimiento aprovisiona los nodos de GPU de NVIDIA con la AMI de NVIDIA de Bottlerocket optimizada para EKS.

  • Karpenter está instalado y configurado en su clúster, ya que en el siguiente procedimiento se utiliza una EC2NodeClass de Karpenter para proporcionar la configuración de segmentación temporal en los datos de usuario del nodo de Bottlerocket. Para obtener más información, consulte Introducción a Karpenter en el sitio web de Karpenter.

  • kubectl configurado para comunicarse con su clúster. Consulte Instalación o actualización de kubectl para obtener más información.

Procedimiento

Agregue la configuración de segmentación temporal a los datos de usuario de Bottlerocket para los nodos de GPU. En el siguiente ejemplo se configuran cuatro ranuras por GPU. La forma en que suministre los datos de usuario depende de cómo aprovisione los nodos. En el siguiente ejemplo, se muestra una EC2NodeClass de Karpenter.

cat <<EOF | kubectl apply -f - apiVersion: karpenter.k8s.aws/v1 kind: EC2NodeClass metadata: name: gpu-bottlerocket-timeslicing spec: amiFamily: Bottlerocket amiSelectorTerms: - alias: bottlerocket@latest role: eksctl-KarpenterNodeRole-<cluster-name> subnetSelectorTerms: - tags: karpenter.sh/discovery: <cluster-name> securityGroupSelectorTerms: - tags: karpenter.sh/discovery: <cluster-name> userData: | [settings.kubelet-device-plugins.nvidia] device-sharing-strategy = "time-slicing" [settings.kubelet-device-plugins.nvidia.time-slicing] replicas = 4 rename-by-default = false fail-requests-greater-than-one = true EOF

Cuando los nodos aprovisionados con esta configuración se unen al clúster, el complemento para dispositivos anuncia cuatro ranuras nvidia.com/gpu para cada GPU física. Los solicita en la especificación de la carga de trabajo junto con las solicitudes o los límites de los recursos del contenedor para el recurso extendido nvidia.com/gpu.

Utilice la segmentación temporal de GPU en los nodos de AL2023 con el complemento para dispositivos de NVIDIA

En AL2023, instale el complemento para dispositivos de NVIDIA tal y como se describe en Instalación del complemento para dispositivos de Kubernetes de NVIDIA y proporcione la configuración de segmentación temporal en un ConfigMap.

Requisitos previos

  • Un clúster de Amazon EKS con nodos que utilizan tipos de instancia de GPU de NVIDIA y la AMI de NVIDIA de AL2023 optimizada para EKS.

  • Si tiene Helm instalado en su entorno de línea de comandos, consulte las instrucciones de configuración de Helm para obtener más información.

  • kubectl configurado para comunicarse con su clúster. Consulte Instalación o actualización de kubectl para obtener más información.

Procedimiento

  1. Cree el ConfigMap de segmentación temporal en el espacio de nombres nvidia, donde instaló el complemento para dispositivos en Instalación del complemento para dispositivos de Kubernetes de NVIDIA. En este ejemplo, se configuran cuatro ranuras por GPU.

    cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ConfigMap metadata: name: nvidia-device-plugin-config namespace: nvidia data: config.yaml: | version: v1 sharing: timeSlicing: renameByDefault: false failRequestsGreaterThanOne: true resources: - name: nvidia.com/gpu replicas: 4 EOF
  2. Actualice la versión existente del complemento para dispositivos de NVIDIA para hacer referencia al ConfigMap con el valor config.name. El indicador --reuse-values conserva los valores que estableció al instalar el complemento para dispositivos en Instalación del complemento para dispositivos de Kubernetes de NVIDIA.

    helm upgrade nvdp nvdp/nvidia-device-plugin \ --namespace nvidia \ --reuse-values \ --set config.name=nvidia-device-plugin-config
nota

El complemento para dispositivos no se recarga automáticamente cuando cambia el ConfigMap. Después de actualizar la configuración de segmentación temporal, reinicie los pods del complemento para dispositivos para aplicar el cambio.

Verificación de que la segmentación temporal de la GPU esté activa

Cuando los nodos con segmentación temporal estén Ready, confirme que el complemento para dispositivos anuncie el número esperado de ranuras y que los pods compartan una GPU física.

nota

La comprobación del UUID compartido de este procedimiento demuestra la segmentación temporal con mayor claridad cuando los pods aterrizan en la misma GPU física. En un nodo con una sola GPU, el complemento para dispositivos anuncia cuatro ranuras y los cuatro pods comparten esa GPU, por lo que muestran el mismo UUID. En un nodo con varias GPU físicas, el programador puede colocar los pods en diferentes GPU. Estos pods muestran diferentes UUID aunque la segmentación temporal esté activa. Para demostrar que se comparte en una GPU, programe la carga de trabajo en un tipo de instancia de una sola GPU. Por ejemplo, agregue un selector de nodos, como node.kubernetes.io/instance-type: g6.2xlarge, a la especificación del pod.

  1. Confirme que el nodo anuncie el número configurado de ranuras de GPU. Con cuatro ranuras por GPU, un nodo con una GPU física informa de 4.

    kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"

    Un ejemplo de salida sería el siguiente.

    NAME GPU ip-192-168-11-225.us-west-2.compute.internal 4
  2. Cree una implementación que ejecute cuatro réplicas, cada una de las cuales solicite una ranura de GPU.

    cat <<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: timeslicing-demo spec: replicas: 4 selector: matchLabels: app: timeslicing-demo template: metadata: labels: app: timeslicing-demo spec: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule containers: - name: cuda image: nvidia/cuda:12.6.0-base-ubuntu22.04 command: ["bash", "-c", "nvidia-smi --query-gpu=uuid --format=csv,noheader; sleep infinity"] resources: limits: nvidia.com/gpu: 1 EOF
  3. Confirme que los cuatro pods estén programados en el mismo nodo.

    kubectl get pods -l app=timeslicing-demo -o wide
  4. Confirme que los cuatro pods informen del mismo UUID de GPU. Un único UUID compartido en los cuatro pods confirma que una GPU física se está multiplexando en el tiempo.

    kubectl logs -l app=timeslicing-demo --prefix

    Un ejemplo de salida sería el siguiente.

    [pod/timeslicing-demo-xxxxxxxxxx-aaaaa/cuda] GPU-c0583cce-87c5-c736-db7f-6d3128c84d03 [pod/timeslicing-demo-xxxxxxxxxx-bbbbb/cuda] GPU-c0583cce-87c5-c736-db7f-6d3128c84d03 [pod/timeslicing-demo-xxxxxxxxxx-ccccc/cuda] GPU-c0583cce-87c5-c736-db7f-6d3128c84d03 [pod/timeslicing-demo-xxxxxxxxxx-ddddd/cuda] GPU-c0583cce-87c5-c736-db7f-6d3128c84d03