使用GPU#

本文档提供了使用 KubeRay 进行 GPU 使用的技巧。

要在 Kubernetes 上使用 GPU,需要配置您的 Kubernetes 设置,并在您的 Ray 集群配置中添加额外的值。

要了解不同云上的GPU使用情况,请参阅 GKEEKSAKS 的说明。

快速入门:提供基于GPU的StableDiffusion模型#

你可以在文档的 示例 部分找到几个 GPU 工作负载示例。 StableDiffusion 示例 是一个不错的起点。

基于GPU的机器学习依赖项#

Ray Docker Hub 托管了基于CUDA的容器镜像,这些镜像打包了Ray和某些机器学习库。例如,镜像 rayproject/ray-ml:2.6.3-gpu 非常适合使用Ray 2.6.3运行基于GPU的ML工作负载。Ray ML镜像打包了这些文档中使用的Ray库所需的依赖项(如TensorFlow和PyTorch)。要添加自定义依赖项,请使用以下两种方法之一或两者:

为 GPU 使用配置 Ray Pod#

使用 Nvidia GPU 需要在 RayClusterheadGroupSpec 和/或 workerGroupSpecs 的容器字段中指定 nvidia.com/gpu 资源的 limitsrequests

以下是一个 RayCluster 工作组配置片段,最多支持 5 个 GPU 工作节点。

groupName: gpu-group
replicas: 0
minReplicas: 0
maxReplicas: 5
...
template:
    spec:
     ...
     containers:
      - name: ray-node
        image: rayproject/ray-ml:2.6.3-gpu
        ...
        resources:
         nvidia.com/gpu: 1 # Optional, included just for documentation.
         cpu: 3
         memory: 50Gi
        limits:
         nvidia.com/gpu: 1 # Required to use GPU.
         cpu: 3
         memory: 50Gi
         ...

群组中的每个 Ray pod 都可以调度在 AWS p2.xlarge 实例上(1 个 GPU,4 个 vCPU,61Gi RAM)。

小技巧

GPU 实例是昂贵的 – 考虑为您的 GPU Ray 工作者设置自动扩展,如上述 minReplicas:0maxReplicas:5 设置所示。要启用自动扩展,还要记得在 RayCluster 的 spec 中设置 enableInTreeAutoscaling:True。最后,确保您配置了 GPU Kubernetes 节点的组或池,以进行自动扩展。有关自动扩展节点池的详细信息,请参阅您的 云提供商的文档

GPU 多租户#

如果一个 Pod 在其资源配置中不包含 nvidia.com/gpu,用户通常期望该 Pod 对任何 GPU 设备无感知,即使它被调度到一个 GPU 节点上。然而,当 nvidia.com/gpu 未被指定时,NVIDIA_VISIBLE_DEVICES 的默认值变为 all,使得 Pod 能够感知节点上的所有 GPU 设备。这种行为并非 KubeRay 独有,而是 NVIDIA 已知的问题。一个变通方法是,在不需要 GPU 设备的 Pod 中将 NVIDIA_VISIBLE_DEVICES 环境变量设置为 void

一些有用的链接:

GPUs 和 Ray#

本节讨论在 Kubernetes 上运行的 Ray 应用程序的 GPU 使用情况。有关 Ray 中 GPU 使用的常规指导,另请参阅 加速器支持

KubeRay 操作符向 Ray 调度器和 Ray 自动缩放器通告容器 GPU 资源限制。特别是,Ray 容器的 ray start 入口点将自动配置适当的 --num-gpus 选项。

GPU 工作负载调度#

在部署了可以访问GPU的Ray pod之后,它将能够执行带有gpu请求注释的任务和角色。例如,装饰器 @ray.remote(num_gpus=1) 注释了一个需要1个GPU的任务或角色。

GPU 自动扩展#

Ray 自动扩展器了解每个 Ray 工作组中的 GPU 容量。假设我们有一个如上配置片段中配置的 RayCluster:

  • Ray 的 Pod 有一个工作组,每个 Pod 都有 1 单位的 GPU 容量。

  • Ray 集群当前没有该组的任何工作节点。

  • maxReplicas 对于该组至少为 2。

然后,以下 Ray 程序将触发 2 个 GPU 工作节点的扩展。

import ray

ray.init()

@ray.remote(num_gpus=1)
class GPUActor:
    def say_hello(self):
        print("I live in a pod with GPU access.")

# Request actor placement.
gpu_actors = [GPUActor.remote() for _ in range(2)]
# The following command will block until two Ray pods with GPU access are scaled
# up and the actors are placed.
ray.get([actor.say_hello.remote() for actor in gpu_actors])

程序退出后,角色将被垃圾回收。GPU工作节点将在空闲超时后缩减(默认60秒)。如果GPU工作节点运行在Kubernetes节点的自动扩展池中,Kubernetes节点也将被缩减。

请求GPU#

您也可以向 自动扩展器 直接请求以扩展GPU资源。

import ray

ray.init()
ray.autoscaler.sdk.request_resources(bundles=[{"GPU": 1}] * 2)

在节点被扩展后,它们将持续存在,直到请求被明确覆盖。以下程序将移除资源请求。

import ray

ray.init()
ray.autoscaler.sdk.request_resources(bundles=[])

GPU 工作节点随后可以缩减规模。

覆盖 Ray GPU 容量(高级)#

对于专业用途,可以覆盖 Ray pod 向 Ray 报告的 GPU 容量。为此,请为头节点或工作组 rayStartParamsnum-gpus 键设置一个值。例如,

rayStartParams:
    # Note that all rayStartParam values must be supplied as strings.
    num-gpus: "2"

Ray 调度器和自动扩展器将为组中的每个 Ray pod 计算 2 个 GPU 容量单位,即使容器限制没有表明 GPU 的存在。

GPU 吊舱调度 (高级)#

GPU 污点和容忍#

备注

托管的 Kubernetes 服务通常会为你处理与 GPU 相关的污点和容忍度。如果你使用的是托管的 Kubernetes 服务,你可能不需要担心这一部分。

Kubernetes 的 Nvidia gpu 插件 对 GPU 节点应用 污点;这些污点阻止非 GPU Pod 被调度到 GPU 节点上。像 GKE、EKS 和 AKS 这样的托管 Kubernetes 服务会自动将匹配的 容忍 应用到请求 GPU 资源的 Pod 上。容忍是通过 Kubernetes 的 ExtendedResourceToleration 准入控制器 来应用的。如果你的 Kubernetes 集群没有启用这个准入控制器,你可能需要手动为每个 GPU Pod 配置添加一个 GPU 容忍。例如,

apiVersion: v1
kind: Pod
metadata:
 generateName: example-cluster-ray-worker
 spec:
 ...
 tolerations:
 - effect: NoSchedule
   key: nvidia.com/gpu
   operator: Exists
 ...
 containers:
 - name: ray-node
   image: rayproject/ray:nightly-gpu
   ...

节点选择器和节点标签#

为了确保 Ray pod 绑定到满足特定条件的 Kubernetes 节点(例如存在 GPU 硬件),您可能希望使用 workerGroup 的 pod 模板 spec 中的 nodeSelector 字段。有关 Pod 到节点分配的更多信息,请参阅 Kubernetes 文档

进一步的参考和讨论#

阅读关于 Kubernetes 设备插件 这里,关于 Kubernetes GPU 插件 这里,以及关于 Nvidia 的 Kubernetes GPU 插件 这里