K8S中GPU资源请求与限制

以下均为个人理解,如果有错误,请各位达人不吝批评指正!

需要提前说一句:
对于 GPU 这类可扩展资源 (Extended Resources),requests 和 limits 的行为与 CPU/内存截然不同。在绝大多数情况下,requests 和 limits 必须相等,否则 Pod 将无法创建。

接下来,简单讲一下GPU资源请求与限制

1. 基础原理:为什么 GPU 的 requests 和 limits 必须相等?

要理解这一点,我们必须回到 Kubernetes 资源模型设计的初衷。

  • 对于 CPU/内存 (可压缩/可限制资源):
    • requests: 是调度时的保证。kube-scheduler 用它来寻找有足够资源的节点。kubelet 确保节点上所有 Pod 的 requests 总和不超过节点的 allocatable。这是 Pod 最低限度的保障。
    • limits: 是运行时的上限。kubelet 通过 Cgroups (Linux 控制组) 强制执行这个限制。CPU 超限会被“节流”(throttled),内存超限会被“杀死”(OOMKilled)。
    • requests <= limits 的设计,允许了资源的“可突发性”(Burstable),即 Pod 在需要时可以尝试使用超过其 requests 但不超过 limits 的资源。
  • 对于 GPU (不可压缩资源):
    • 核心差异: kubelet 和底层的容器运行时 (containerd/Docker) 没有原生的机制去“限制”或“节流”GPU 的使用。GPU 不是一个可以像 CPU 时间片那样被轻易切分和限制的资源。一张 GPU 卡一旦分配给一个容器,容器内的程序就可以使用其 100% 的算力和显存,kubelet 无法对此进行约束。
    • 设计决策: 基于这个底层限制,Kubernetes 做出了一个务实的设计决策:不支持 GPU 资源的“突发”。为了避免语义上的混淆和无法履行的“承诺”,API Server 在准入阶段就强制要求:

For extended resources, limit must be equal to request.

    • 结论: 你必须同时写 requests 和 limits,并且它们的值必须完全一样。只写其中一个,或者两者不等,API Server 都会拒绝你的 Pod 创建请求。

正确的基础示例:

apiVersion: v1
kind: Pod
metadata:
  name: cuda-pod
spec:
  containers:
  - name: my-container
    image: nvidia/cuda:11.8.0-base-ubuntu22.04
    resources:
      limits:
        nvidia.com/gpu: "1" # < 请求 1 个 GPU
      requests:
        nvidia.com/gpu: "1" # < 限制也必须是 1

2. 最新技术方案:从“整数卡”到“精细化请求”

随着技术的发展,我们请求的早已不只是一张“整数卡”。下面我们看看在不同的技术方案下,requests 和 limits 的具体应用。

方案一:基于时间片的 GPU 共享 (如 a GPU)

在这种软件虚拟化方案下,我们请求的不再是 nvidia.com/gpu,而是由 Device Plugin 定义的虚拟化资源

  • 请求的是什么: 你请求的是一个“使用权”和一份“显存配额”。
  • 底层原理:
    1. Device Plugin 向上层 kubelet 上报的是自定义资源,如 aliyun.com/gpu-mem,其单位可以是显存的 GiB 或 MiB。
    2. 用户在 Pod Spec 中请求这些自定义资源。同样,requests 和 limits 必须相等。
    3. kubelet 在分配时,会调用 Device Plugin 的 Allocate 接口。Device Plugin 此时会记录下这个容器的显存配额,并通过 LD_PRELOAD 注入一个动态库,在运行时强制执行这个显存限制。
  • 示例:

resources:
  limits:
    aliyun.com/gpu-mem: "4" # 请求 4GiB 的显存配额和相应的算力时间片
  requests:
    aliyun.com/gpu-mem: "4" # 同样必须相等

方案二:NVIDIA MIG (硬件级虚拟化)

这是目前实现精细化请求最可靠的方式,因为它有硬件级的保障。

  • 请求的是什么: 你请求的是一个特定规格的、物理隔离的 GPU 实例 (GI)
  • 底层原理:
    1. 管理员使用 nvidia-smi 将物理 GPU 划分为不同的 MIG Profile,例如 1g.5gb 或 3g.20gb
    2. NVIDIA 的 Device Plugin 会自动发现这些 GI,并上报为不同的可扩展资源,如 nvidia.com/mig-1g.5gb: 7
    3. 用户在 Pod Spec 中可以直接请求这些具体的 MIG 设备。requests 和 limits 依然必须相等。
  • 示例:

resources:
  limits:
    nvidia.com/mig-1g.5gb: "1" # 精确请求一个 1g.5gb 规格的 MIG 实例
  requests:
    nvidia.com/mig-1g.5gb: "1" # 必须相等

专家提示: 使用 MIG 时,你请求的资源名称是一个具体的“型号”,而不是一个泛指的 gpu

方案三:动态资源分配 (DRA) - 未来方向

DRA 彻底改变了资源请求的模式,使其更加灵活和富有表现力。

  • 请求的是什么: 不再直接在 Pod 的 resources 中请求,而是通过一个**ResourceClaim 对象**来声明你的需求。
  • 底层原理:
    1. 定义 (ResourceClass): 管理员定义一个 ResourceClass,描述一类 GPU 资源的特性和参数,例如 name: mig-a100
    2. 声明 (ResourceClaim): 用户创建一个 ResourceClaim,引用 ResourceClass 并填写具体的参数。

# ResourceClaim.yaml
apiVersion: resource.k8s.io/v1alpha2
kind: ResourceClaim
metadata:
  name: my-gpu-claim
spec:
  resourceClassName: mig-a100
  parameters: # < 这是核心,可以传递任意参数
    migProfile: "1g.5gb"
    memory: ">=4Gi"

    1. 在 Pod 中引用: 在 Pod Spec 中,通过 resourceClaims 字段引用这个声明。

# Pod.yaml
spec:
  resourceClaims:
  - name: gpu # 在容器内引用的名称
    source:
      resourceClaimName: my-gpu-claim # 引用上面创建的 Claim
  containers:
  - name: my-container
    resources: # 注意这里的变化
      claims:
      - name: gpu # 引用在 Pod 层面定义的 claim

  • 优势: 这种模式将“需要什么”(What) 与“分配哪个”(Which)彻底解耦。Pod 只需声明需求,而底层的 DRA 驱动会负责去寻找和分配一个满足需求的具体设备。requests 和 limits 的概念在这里被更富表现力的 ResourceClaim 所取代。

靠谱的实践

  1. 铁律: 在使用传统的 Device Plugin 模型时(无论是整卡、GPU Sharing 还是 MIG),GPU 资源的 requests 和 limits 必须相等。这是由 Kubernetes 对不可压缩资源的设计所决定的。
  2. 语义清晰:
    • 请求 nvidia.com/gpu: 1 意味着:“我需要一张完整的、未被 MIG 分割的物理 GPU 卡的独占使用权”。
    • 请求 aliyun.com/gpu-mem: N 意味着:“我需要在一张共享的 GPU 卡上获得 N GiB 的显存配额和相应比例的时间片算力”。
    • 请求 nvidia.com/mig-1g.5gb: 1 意味着:“我需要一个硬件隔离的、规格为 1g.5gb 的 MIG 实例的独占使用权”。
  3. 未来方向: 积极关注并逐步采纳 DRA (动态资源分配)。尽管它目前还处于 Alpha/Beta 阶段,但它代表了 Kubernetes 异构资源管理的未来。它通过 ResourceClaim 提供了远超 requests/limits 的表达能力,是解决复杂硬件资源请求的根本之道。
07-15
Kubernetes 中,管理和调度 GPU 资源是支持机器学习训练、图形渲染等高性能计算任务的关键环节。为了实现高效的 GPU 资源管理调度,需要结合硬件驱动、插件系统以及调度策略进行综合配置。 ### 1. GPU 设备的识别注册 Kubernetes 原生并不直接支持 GPU 资源的识别和使用,必须依赖设备插件(Device Plugin)机制来完成资源注册。NVIDIA 提供了官方的设备插件 `nvidia-device-plugin`,它能够自动检测节点上的 GPU 并向 Kubernetes 注册可用资源[^4]。 执行以下命令可以验证节点是否已正确注册 GPU 资源: ```bash kubectl describe node <node-name> | grep nvidia.com/gpu ``` 如果系统中启用了 MIG(Multi-Instance GPU),还可以看到类似如下的输出,表示不同规格的 MIG 实例数量: ``` nvidia.com/mig-1g.10gb: 1 nvidia.com/mig-2g.20gb: 2 ``` 若未更新资源信息,可尝试重启 `nvidia-device-plugin` 后再次查看。 ### 2. 安装配置 NVIDIA GPU Operator NVIDIA 提供的 GPU Operator 是一套自动化部署工具,集成了驱动安装、容器运行时配置、设备插件部署等功能,极大地简化了 GPU 环境的搭建过程。通过 Helm Chart 可以一键部署完整的 GPU 支持环境,确保用户能够高效、安全地使用 GPU 算力资源[^3]。 GPU Operator 的主要优势包括: - 自动维护 GPU 设备状态 - 集成 CUDA 库和容器运行时支持 - 支持多种 GPU 架构和拓扑结构 安装方式示例如下: ```bash helm repo add nvidia https://nvidia.github.io/gpu-operator helm install --wait gpu-operator nvidia/gpu-operator ``` ### 3. Pod 中指定 GPU 资源请求 在定义 Pod 时,可以通过 `.spec.containers[].resources.limits` 字段指定对 GPU 资源的需求。例如,以下 YAML 片段展示了如何请求一个 GPU: ```yaml apiVersion: v1 kind: Pod metadata: name: cuda-vector-add spec: containers: - name: cuda-vector-add image: "k8s.gcr.io/cuda-vector-add:v0.1" resources: limits: nvidia.com/gpu: 1 # 请求 1 个 GPU ``` 如果使用 MIG 技术,则可以更细粒度地指定具体类型的 MIG 实例: ```yaml resources: limits: nvidia.com/mig-1g.10gb: 1 ``` ### 4. 调度策略优化 Kubernetes 的默认调度器已经支持基于 GPU 资源的调度逻辑。但在实际生产环境中,建议结合以下策略进一步优化调度行为: - **优先级抢占**:为高优先级任务分配更高权重,必要时允许抢占低优先级任务占用的 GPU。 - **拓扑感知调度**:考虑 GPU CPU、内存之间的拓扑关系,提升数据传输效率。 - **多租户隔离**:通过命名空间配合配额限制,防止某些项目或用户过度消耗 GPU 资源[^5]。 ### 5. 监控调优 推荐使用 Prometheus + Node Exporter + DCGM Exporter 组合监控 GPU 使用情况,实时掌握各节点的 GPU 利用率、温度、功耗等指标,并据此调整资源分配策略。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值