news 2026/9/12 4:34:44

海光DCU接入K8s:整卡、共享与vDCU调度实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
海光DCU接入K8s:整卡、共享与vDCU调度实战解析

如果你接过“把一批海光 DCU 节点接进 Kubernetes,再让上层 AI 平台和 DeepSeek 推理服务跑起来”这种需求,第一反应大概率是:装个驱动、部署个 Device Plugin 不就行了?真动手之后才会发现,整卡、共享、vDCU 虚拟化是三套完全不同的调度模型,平台侧的资源配额和监控要跟着改,DeepSeek 这种大模型部署时还有一堆显存和镜像的坑。这篇文章把我这次把海光 DCU 接入 Kubernetes 和 CubeStudio 的完整实操链路拆开讲清楚,重点覆盖整卡调度、共享调度、两种 vDCU 虚拟化方案的实现差异,最后用一份 DeepSeek 7B 推理服务的部署配置收尾。正在做 AI 基础平台、或者刚拿到一批 DCU 机器准备纳入云平台的工程师,可以直接按这套思路去推。

1. 先搞清楚:K8s 里的 DCU 调度为什么这么麻烦

1.1 设备插件是 DCU 进 K8s 的唯一通道

K8s 本身并不知道 DCU 是什么,它只认识 CPU、内存、磁盘这类内置资源。异构计算设备想被 K8s 调度,必须走 Device Plugin 机制。

Device Plugin 是一个跑在每个节点上的 gRPC 服务,通过 Unix socket 跟 kubelet 通信,默认监听在/var/lib/kubelet/device-plugins/目录下。它要实现的核心接口就两个:ListAndWatchAllocate

  • ListAndWatch:启动时向 kubelet 上报“这个节点上有多少张 DCU”,平时持续上报设备健康状态。如果某张卡坏了,插件通知 kubelet 把它从可用列表里摘掉。
  • Allocate:当调度器把 Pod 派到节点上、kubelet 准备启动容器时,插件需要返回一组信息:容器要挂载哪些设备文件、要注入哪些环境变量、要映射宿主机的哪些目录。

所以 DCU 想进 K8s,第一件事不是写调度器,而是先有一个能跟 kubelet 对话的 Device Plugin。插件注册成功后,kubelet 会把资源名写进节点状态里的 Capacity 和 Allocatable 字段,比如hygon.com/dcu: 8,kube-scheduler 只有看到这个数字,才可能在后续调度时把任务派到这个节点。

还有一个容易忽略的点:宿主机上装了驱动,容器里不一定能用。容器有独立的设备命名空间,宿主机上的/dev/kfd/dev/dri/renderDxxx这些设备节点,容器里默认是看不到的。Device Plugin 在 Allocate 阶段干的核心事,就是把 DCU 的设备节点、依赖的驱动库、以及类似ROCR_VISIBLE_DEVICES这样的环境变量全部注入到容器 spec 里。这一步不做对,后面所有层级的资源调度全是空的。

1.2 三种调度形态,本质是三种资源粒度

标题里说的“整卡 / 共享 / 两种 vDCU 虚拟化”,落到 K8s 里其实是三套不同的资源粒度和隔离模型。

调度形态资源命名示例隔离类型资源粒度
整卡直通hygon.com/dcu物理隔离1 张卡
共享切分hygon.com/dcu-share软件切分,弱隔离每张卡切成 N 个单位,可小数申请
vDCU 硬件切片hygon.com/vdcu-physical驱动/固件级切片按比例切分,独占算力与显存
vDCU 时间片hygon.com/vdcu-time驱动级时分复用按时间片轮转,可超卖

搞这四套资源模型的时候,我才真正理解为什么有人会说“GPU 调度难”。CPU 有 cgroup 可以做配额控制,内存有 cgroup 做硬性限制,但 DCU 的显存分配根本不经过 cgroup,算力隔离更是完全依赖驱动层的能力。你想把一张卡拆给两个任务用,不是给每个任务发一把钥匙就行,还要解决“任务 A 吃满算力把任务 B 饿死”的问题。这就是为什么整卡容易做,而共享和 vDCU 需要单独设计。

1.3 一次调度请求的完整链路

整条链路是这样的:用户提交 Pod,声明需要多少 DCU 资源 → scheduler 根据节点 Allocatable 判断哪个节点放得下 → 把 Pod 绑定到该节点 → kubelet 调用 Device Plugin 的 Allocate 接口 → 插件返回需要注入的设备节点、环境变量和挂载点 → 容器运行时按这些参数启动容器。

这里有一个关键细节:DCU 这类扩展资源和 CPU/内存不一样,K8s 要求 requests 和 limits 必须一致,不能只写 requests 不写 limits。写错了会直接导致 Allocate 阶段不触发,容器起来之后根本看不到设备。这个我后面在踩坑部分还会细说。

2. 节点侧准备:驱动、运行时与设备可见性检查

2.1 节点层面的驱动与 DTK 安装

要让 DCU 正常工作,节点上至少需要两层的软件:内核驱动和用户态 DCU Toolkit(海光那边通常叫 DTK,兼容 ROCm/HIP 生态)。

先装内核驱动。安装完之后确认模块加载正常,我习惯用lsmod | grep amdgpu这类命令检查,也可以在/dev下看有没有对应的设备节点生成。然后装 DTK,它提供 HIP 运行时、数学库和编译器,装好之后建议统一放到/opt/dtk/usr/local这种全局目录,保证节点上所有用户都能访问。

这里最容易被坑的是版本匹配。DTK 对驱动版本有明确要求,驱动太老或太新都可能导致hipInit直接失败,或者 SMI 工具能识别到卡但容器里加载不了库。我们后来是把驱动版本和 DTK 版本锁定成一个组合,写进基线部署文档,新节点起机时按同一个组合装,才彻底消停。如果你用容器镜像来跑任务,镜像里的 DTK 版本也必须和宿主机驱动匹配,否则容器内程序调用 HIP API 时会报各种诡异的符号错误。

安装完驱动之后,一定要在节点上先确认设备可见性,别急着接 Kubernetes。跑一下驱动自带的 SMI 工具(不同版本命令名可能不一样,常见的有rocm-smihy-smidcu-smi),确认能看到卡数和显存总量。再用rocminfo这类工具看一下设备 agent 是否正常,如果列表里是空的,说明驱动栈有问题,先解决这个再往下走。

2.2 容器运行时怎么把 DCU 设备送进容器

节点驱动装好了只是第一步,还得让容器运行时知道怎么把设备送进去。现在比较推荐的是走 CDI(Container Device Interface)。

CDI 的思路是,把设备信息写成一个 JSON/TOML 描述文件放到/etc/cdi/目录,containerd 在启动容器时根据声明自动挂载对应的设备节点和库目录。相比传统方案里的 privileged 容器,CDI 的权限控制更精细,平台侧的维护成本也低。

如果设备插件本身支持在 Allocate 阶段直接返回设备节点,不依赖 CDI 也能跑通,只是后面做共享、vDCU 这种复杂分配时,插件返回的内容会很重。所以我的建议是:如果你在用 containerd,尽早把 CDI 打开,后面所有 DCU 设备的注入逻辑都统一走 CDI,kubelet 和运行时之间的配合会清爽很多。

2.3 节点是否已经“准备好”被调度

节点侧准备到什么程度算完成?我习惯按三个标准检查:

  1. 节点终端执行 SMI 工具能列出所有 DCU,显存容量正确;
  2. /dev/kfd/dev/dri设备节点存在,权限正常;
  3. 部署完 Device Plugin 后,kubectl describe node能在 Capacity 里看到 DCU 资源。

如果前两步正常,但kubectl describe node里没有资源,问题基本都出在 Device Plugin 没起来,或者插件与 kubelet 的 socket 通信异常。优先看插件 Pod 的日志,常见的失败原因是 socket 目录权限不对、插件 Pod 挂载的/dev不完整。

3. CubeStudio 平台适配:把 DCU 变成可申请的资源

3.1 自定义资源上报与应用感知

当 Device Plugin 正常注册后,节点上会出现类似这样的信息:

Allocatable: cpu: 128 memory: 512Gi hygon.com/dcu: 8

注意,这里默认是整卡数字。也就是说,K8s 原生调度的最小单位是“一张卡”。用户想申请一张卡,Pod 里这样写:

resources: requests: hygon.com/dcu: 1 limits: hygon.com/dcu: 1

这种整数卡模式是平台能感知 DCU 的最小闭环。在 CubeStudio 里,管理员只需要在资源类型配置里新增hygon.com/dcu这个资源项,用户在项目配额里申请 DCU 数量,提交训练或推理任务时选择资源类型,平台后端把这段 yaml 拼到 Pod spec 里,调度就能工作了。

但这个阶段你也会立刻遇到第一个限制:用户需要 0.5 张卡,怎么办?平台界面根本没法表达 0.5 这个数字,因为底层 Allocatable 是 8 而不是 40。这就要靠下一节的调度扩展来解决了。

3.2 调度策略:默认调度器 vs 扩展调度器

默认的 kube-scheduler 在面对 DCU 时比较“笨”,它只做数量匹配:节点剩多少张卡,够就放行,不够就等。它不管卡间拓扑,不管显存是否能容纳模型,更不管哪张卡已经满载、哪张还是空闲的。

所以像 CubeStudio 这类 AI 平台接 DCU,通常不是只用默认调度器,而是引入自定义调度能力。市面上的方案基本两类:

  • scheduler extender:在默认调度器外面挂一个 HTTP 扩展服务,预选和优选阶段多问一层“这个 Pod 的 DCU 资源在哪个节点/哪张卡上最合适”。
  • 平台自研调度器:直接替换 kube-scheduler,把 DCU 资源、GPU 拓扑、显存占用、任务优先级全纳入调度计算。

我们这轮用的思路是:整卡场景继续用默认调度器,共享和 vDCU 场景走扩展调度器。因为共享切分后的“资源单位”是虚拟的,默认调度器根本不知道 5 个共享单位和 1 张卡之间有什么换算关系,必须由扩展层来维护这张映射表。

3.3 CubeStudio 的资源模型对接

CubeStudio 的适配工作,主要集中在三块:

  • 资源类型配置:新增 DCU 整卡、DCU 共享单位、vDCU(物理切片/时间片)这几类资源,并为每类资源定义配额单位。比如整卡按“卡”计,共享单位按“个”计,vDCU 按“实例”计。
  • 任务模板透传:平台的任务模板要能把用户选择的资源类型翻译成 K8s 的 requests/limits 字段,同时把对应资源名拼对。这里最容易出错的就是资源名字符串不一致,比如平台配置里写了hygon.com/dcu,但 Device Plugin 上报的是hygon.com/dcu-v1,两边对不上,界面会一直显示资源不足。
  • 集群监控接入:让平台监控大盘能看到每张 DCU 的利用率、显存占用、温度、功耗。这个一般靠厂商提供的 DCU exporter 采集 SMI 指标,然后接到 Prometheus 体系里。监控不做的话,用户跑任务时完全是个盲盒,只能靠猜。

平台侧改造看着都是些杂活,但恰恰是上线后用户体感最明显的部分。资源模型定义清楚,后续共享和 vDCU 的推进才顺。

4. 整卡调度:一张卡完整交给一个容器的实现

4.1 部署 Device Plugin:DaemonSet 与权限细节

整卡调度是所有调度方式里最稳的,也是必须优先跑通的。我们先部署一个基础的 Device Plugin DaemonSet,类似这样:

apiVersion: apps/v1 kind: DaemonSet metadata: name: hygon-dcu-device-plugin namespace: kube-system spec: selector: matchLabels: name: hygon-dcu-device-plugin template: metadata: labels: name: hygon-dcu-device-plugin spec: hostNetwork: true containers: - name: device-plugin image: registry.example.com/hygon/dcu-device-plugin:latest securityContext: privileged: true volumeMounts: - name: device-plugin mountPath: /var/lib/kubelet/device-plugins - name: sys mountPath: /sys readOnly: true - name: dev mountPath: /dev volumes: - name: device-plugin hostPath: path: /var/lib/kubelet/device-plugins - name: sys hostPath: path: /sys - name: dev hostPath: path: /dev

三个挂载点对应三类需求:

  • /var/lib/kubelet/device-plugins:插件注册 socket 的位置,必须和 kubelet 一致;
  • /dev:插件需要探测 DCU 设备节点,还要在 Allocate 时把设备文件映射进容器;
  • /sys:很多厂商的设备插件通过 sysfs 读取设备拓扑或性能属性。

插件部署起来后,去kubectl logs看插件启动日志,正常情况下会看到类似“register to kubelet success”的输出。再kubectl describe node看节点的 Allocatable,如果出现了hygon.com/dcu,说明整卡能力已经打通。

4.2 应用侧声明资源

应用侧很简单,只要在 Pod 里声明:

apiVersion: v1 kind: Pod metadata: name: dcu-test spec: restartPolicy: OnFailure containers: - name: dcu-test image: registry.example.com/hygon/pytorch-dtk:latest command: ["rocm-smi"] resources: requests: hygon.com/dcu: 1 limits: hygon.com/dcu: 1

跑起来之后,如果一切正常,rocm-smi只会在容器里看到 1 张 DCU,虽然宿主机上有 8 张。这正是设备插件做了ROCR_VISIBLE_DEVICES这类环境变量隔离的结果。

4.3 整卡调度的局限

整卡好归好,但它有一个绕不开的浪费问题。一张 32GB 的卡,如果业务只是跑一个 7B 模型的推理服务,显存可能就用掉 14GB 左右,算力利用率往往只有个位数百分比。但别的任务又因为“没有整卡额度”而排队。

我见过最典型的场景:节点上 8 张卡全部分配出去了,每张卡的实际利用率不到 10%,新任务进不来。这时候就算你强行用整卡对外提供服务,用户也会疯狂吐槽资源不够。所以整卡只适合模型训练、推理并发高、显存需求接近满载的场景,一旦业务碎片化,就必须上共享或者 vDCU。

5. 共享调度:把一张卡拆成多个资源单位

5.1 共享的真正难点:隔离而不是切分

共享调度的难点不在“能不能把一张卡给多个容器用”,而在“多个任务挤在一块之后,它们之间会不会互相伤害”。

CPU 有 cgroup 做时间片控制,内存有 cgroup 做硬限制,但 DCU 的显存和算力没有 cgroup 机制可以直接管。两个容器如果被分配到同一张物理卡上,哪怕各自声明了“我只要 20% 算力”,驱动也不会真的只给它 20%——如果没有额外的虚拟化层去限制,任务 A 可能直接把算力吃满,任务 B 的推理延迟立刻飙升。

另一个风险是显存超卖。共享调度如果只切“数量”不看“显存”,两个任务可能同时申请显存,导致物理显存耗尽,驱动报 out of memory,最严重的时候整张卡上的任务全部崩掉。

所以,共享调度落地之前,必须先确认驱动或运行时插件到底提供了哪种隔离能力:是完全不隔离、只隔离设备号、还是能做到显存和算力的硬隔离。不同的隔离能力,直接决定了共享单位怎么定义。

5.2 实现共享的两种路径

路径 A 是“资源单位”模式。Device Plugin 把一张物理卡化成 M 个共享单位,比如 M=5,每个单位代表约 20% 的卡资源。Pod 申请 1 个单位,底层映射到同一张物理卡,但每个容器都会被注入同一个物理设备的ROCR_VISIBLE_DEVICES值,所以多个容器能同时看到这张卡,共享使用。

这种模式实现简单,但隔离能力基本为零,一般只适合内部开发测试环境。它解决的问题是“资源位不够分”,不解决“任务互抢”。

路径 B 是“驱动层切分”模式。让驱动或虚拟化层真正介入,每个共享单位拿到独立的显存区段和算力配额。这种情况下,上层 Device Plugin 上报的其实是“虚拟设备”,不是物理卡。这其实就是下一章要讲的 vDCU 虚拟化的一种形态。

5.3 共享调度下的显存与算力配置实战

假如你有一张 32GB 的 DCU,想用共享模式切成 4 个单位,每个单位理论显存 8GB。这时候如果业务方想跑 DeepSeek-R1-Distill-Qwen-7B,fp16 权重就要占 14GB 左右,那么 0.25 卡是绝对放不下的,0.5 卡的理论 16GB 也很勉强,因为还有 KV Cache 和激活值。这种情况我会直接建议:要么申请整卡,要么用量化的模型权重把占用压到 8GB 以内再上共享。

共享模式配置的要点是把事情说在前面:给每个容器设置显存上限,能绑就绑,绑不了宁可不超卖。宁可让每卡的单位数少一点,也不要为了报表好看去挑战物理极限。多跑几次模型加载测试,把真实显存峰值测出来再定切割比例,比拍脑袋切稳得多。

6. 两种 vDCU 虚拟化的实现差异与选型

6.1 第一种 vDCU:硬件切片隔离

第一种 vDCU 走的是硬件切片路线,类似大家熟悉的 MIG 思路。DCU 底层把计算单元、显存控制器和缓存按比例切成多个独立分区,每个分区在物理上互相隔离,拿到一个分区的任务就像独占了一张小卡。

这种模式有几点好处:

  • 一个分区里的任务把算力跑满,不会影响其他分区,性能可预测;
  • 显存是硬件级隔离,不会出现共享模式下的超卖 OOM;
  • 一张卡可以同时跑不同类型的任务,训练和推理混部,互不干扰。

代价是分区粒度通常是固定的,比如只能按 1/2、1/4、1/8 切,不支持“30%”这种随意比例。而且在 K8s 调度上,设备插件要做的事比较多:它需要枚举出这张卡上的所有硬件切片实例,然后把每个切片当作一个独立的资源来上报和分配。

如果平台上的业务都是长期稳定跑的,比如训练任务、高并发推理服务,硬件切片 vDCU 是最理想的形态。

6.2 第二种 vDCU:时间片共享池化

第二种 vDCU 走的是时间片路线。驱动在软件层把计算单元的时间片轮流分配给多个虚拟设备,每个 vDCU 看起来都像独立设备,但底层是同一批物理计算单元的时分复用。

这种模式的优势是密度高、粒度灵活:你能在一张卡上创建出十几个 vDCU,每个 vDCU 的“大小”可以按百分比随意调整,非常适合大量轻量级推理任务、开发调试环境、以及低优先级的批处理任务。

但它的问题也很明显:当几个 vDCU 同时繁忙时,算力会被时间片稀释,任务延迟会出现毛刺。也就是说,它的隔离是“逻辑隔离”不是“物理隔离”,不适合对延迟敏感的生产业务。

6.3 两种 vDCU 的对比与选型

维度硬件切片 vDCU时间片 vDCU
隔离粒度硬件级隔离驱动软件级隔离
显存隔离硬隔离,各分区独享软隔离,可配置上限
算力隔离强,互不干扰弱,繁忙时会争抢
切分粒度固定比例(1/2、1/4 等)任意百分比
单卡可创建数量有限较多,可超卖
适用场景训练服务混部、SLA 明确轻量推理、开发调试、短任务
复杂度设备插件要枚举实例,较复杂配置相对简单

选型上我个人的经验是:先把硬件切片 vDCU 给“吃显存、吃算力、时间长”的业务,比如模型微调、批量推理;把时间片 vDCU 给“占位小、时间短、并发多”的业务,比如 Notebook、在线 demo 服务。

6.4 在设备插件中声明 vDCU 实例

无论哪种 vDCU,接入 K8s 的本质都是把它当成一种新的扩展资源。比如硬件切片 vDCU 可以命名为hygon.com/vdcu-physical,时间片 vDCU 命名为hygon.com/vdcu-time,Device Plugin 启动时根据节点上的 vDCU 实例列表动态上报数量。

用户在 CubeStudio 里申请资源时,其实是在这两种资源之间做选择:

# 申请一个硬件切片 vDCU resources: requests: hygon.com/vdcu-physical: 1 limits: hygon.com/vdcu-physical: 1
# 申请 2 个时间片 vDCU resources: requests: hygon.com/vdcu-time: 2 limits: hygon.com/vdcu-time: 2

这里的数量到底代表多少算力,取决于一个 vDCU 实例的具体规格。平台需要把“vDCU 模板”的概念暴露给用户,比如“32GB 卡的 1/2 硬件切片”“一张卡的 10% 时间片”,用户看到的是几种可选的套餐,而不是原始的数字。

7. DeepSeek 推理服务在 DCU 上的落地实操

7.1 选哪个 DeepSeek 模型:显存估算思路

DeepSeek 全量版本很大,比如 DeepSeek-V3 这种 671B 级别的模型,单机根本跑不动,需要多机多卡的分布式推理,一般项目根本没必要硬上。现实的选择是 DeepSeek-R1-Distill 系列的蒸馏版。

选模型之前先做显存估算。公式很简单:权重显存 ≈ 参数量 × 2 字节(fp16 精度)。再加上 KV Cache、激活值和运行时开销,实际占用一般是权重的 1.3 到 1.5 倍。

模型参数量fp16 权重实际建议显存卡数建议
DeepSeek-R1-Distill-Qwen-7B7B约 14GB32GB+1 张整卡
DeepSeek-R1-Distill-Qwen-14B14B约 28GB64GB 或 2×32GB2 卡张量并行
DeepSeek-R1-Distill-Qwen-32B32B约 64GB4×32GB 或 2×64GB多卡张量并行

以最常见的 32GB DCU 节点为例,首选就是 7B 版本。14B 如果想在单卡上跑,只能做量化,比如 int4 量化后显存能压到 8GB 左右,效果会损失一点,但至少能跑起来。32B 就别想着单卡了,老老实实做张量并行。

7.2 推理框架镜像准备

DCU 上跑推理,框架首选还是 vLLM,但要选支持 ROCm/DTK 的版本,海光生态通常有对应的适配包或镜像。不要浪费时间从源码编译,环境差异太多,编译问题会消耗大量精力。

我们最终用的镜像是在 DTK 基础镜像上叠加 vLLM:

FROM registry.example.com/hygon/dtk-base:24.04 RUN pip install vllm-dtk==0.7.2 COPY --from=models registry.example.com/ai/models:deepseek-7b /models ENV HIP_VISIBLE_DEVICES=0 EXPOSE 8000

7.3 在 CubeStudio 上发布推理服务

模型就绪后,在 CubeStudio 的在线服务模块里创建一个自定义推理服务,本质上提交的是一个 Deployment:

apiVersion: apps/v1 kind: Deployment metadata: name: deepseek-7b-dcu spec: replicas: 1 selector: matchLabels: app: deepseek-7b-dcu template: metadata: labels: app: deepseek-7b-dcu spec: containers: - name: vllm image: registry.example.com/ai/vllm-dtk:0.7.2 command: - python3 - -m - vllm.entrypoints.openai.api_server args: - --model=/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B - --dtype=float16 - --tensor-parallel-size=1 - --max-model-len=32768 - --gpu-memory-utilization=0.92 ports: - containerPort: 8000 resources: limits: hygon.com/dcu: 1 volumeMounts: - name: models mountPath: /models volumes: - name: models persistentVolumeClaim: claimName: model-storage

这里有几个参数值得单独解释:

  • --tensor-parallel-size=1:单卡推理。如果业务选择多卡跑 14B,这里要改并行卡数,同时 resources 里的 DCU 配额也要相应增加。
  • --gpu-memory-utilization=0.92:不要太贪心,留出 8% 给驱动和运行时,否则加载长文本时很容易 OOM。
  • --max-model-len=32768:限制最大上下文长度。不设的话,vLLM 会按模型默认值申请显存,遇到长上下文任务时,KV Cache 可能把显存吃满。

另外再把 Service 暴露出来,如果是内部联调用 NodePort 就行:

apiVersion: v1 kind: Service metadata: name: deepseek-7b-dcu spec: type: NodePort selector: app: deepseek-7b-dcu ports: - port: 8000 targetPort: 8000 nodePort: 30100

7.4 服务验证与性能观察

服务起来之后,用 curl 验证:

curl -X POST http://<node-ip>:30100/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", "messages": [ {"role": "user", "content": "用一句话解释 DCU 调度"} ], "max_tokens": 256 }'

能正常返回就说明链路通了。接下来建议再去 vLLM 的/metrics拉一下指标,重点观察num_requests_runninggpu_cache_usage_perc和 token 生成速度。跑一段时间后你会发现,单卡服务 7B 模型,预填充长文本时显存占用会快速上升,这也是上面为什么要留出显存余量的原因。

8. 踩坑实录:接入过程里最典型的五个问题

8.1 驱动版本与 DTK 不匹配

问题现象:宿主机 SMI 工具能正常看到卡,rocminfo也正常,但容器里的程序初始化 HIP 时直接失败,报错信息语焉不详。

排查过程:先看dmesg,如果能发现 gfx ring timeout 或者驱动固件加载失败之类的日志,十有八九是驱动和 DTK 的版本组合出了问题。再把容器内的 DTK 版本和宿主机的驱动版本逐项比对,基本就是镜像里的 DTK 太新,宿主机驱动没跟上。

解决办法:建立版本基线,驱动和 DTK 用同一个发布周期的组合,镜像构建时锁定 DTK 版本。以后节点扩容、镜像更新前先对照基线检查。

8.2 容器内找不到设备节点

问题现象:Pod 起来了,但进容器一看/dev下没有kfd、没有dri,任务当然跑不起来。

排查过程:这个问题的根因往往不是设备没挂,而是 Pod 的 resources 里只写了 requests,没写 limits,导致 kubelet 认为这个 Pod 不需要做设备分配,Device Plugin 的 Allocate 根本没被调用。

解决办法:扩展资源必须 requests 和 limits 同时写,并且建议两者保持一致。统一规范后,这个坑基本不会再踩。

8.3 共享调度下的显存超卖

问题现象:两个任务被分到同一张卡的共享单位上,一个任务加载模型时,另一个任务直接报显存溢出,严重时整卡服务全部挂掉。

排查过程:一看调度记录,两个容器确实分到了不同共享单位,但设备插件只做了“数量切分”,没有做显存隔离。底层物理显存是同一块,申请总量超过物理上限,驱动只能报错。

解决办法:共享模式下必须给资源单位绑定显存上限,不做显存绑定的场景坚决控制并发数。我们后来把共享单位的定义从“百分比算力”改成“显存 + 算力上限”双约束,才好用一些。但终极方案还是迁移到 vDCU,让驱动层做真正的隔离。

8.4 平台配额和监控不感知新资源

问题现象:节点上明明有 DCU 资源,CubeStudio 提交任务时却提示资源不足,或者配额管理页面根本选不到 DCU。

排查过程:平台资源管理模块里没有注册hygon.com/dcu这个资源类型,所以配额计算时全部按 0 处理。监控大盘看不到 DCU 指标,也是因为没接 DCU exporter。

解决办法:在平台资源类型配置里逐一注册整卡、共享、vDCU 资源名,和 Device Plugin 上报的名字保持一致;监控侧接入 DCU 的 Prometheus exporter。这个环节代码量不大,但涉及平台多个模块,最好留出专门的时间做联调。

8.5 推理服务健康检查误杀

问题现象:DeepSeek 服务部署后,Pod 一直在 CrashLoopBackOff,但日志里看不到明显报错。

排查过程:看事件才发现是存活探针的问题。模型权重从 PVC 加载到初始化完成需要好几分钟,默认的 failureThreshold 几秒钟一失败,Pod 就被 kubelet 重启了。

解决办法:把 startupProbe 或 readinessProbe 的 initialDelaySeconds 调到 600 秒以上,等模型加载完成后再开始探测。如果你用的是 vLLM,健康检查路径可以用/health,比请求/v1/chat/completions要轻量得多,不会把探针请求排进推理队列。

这轮 DCU 接入做下来,我最大的体感是:整卡调度是最容易出成果的部分,但它只是起点;共享调度是平台资源利用率的分水岭,可也是最容易失控的部分;vDCU 真正解决隔离问题,但选硬件切片还是时间片,取决于业务到底怕不怕延迟毛刺。如果你也在做类似的事情,先别急着追求炫酷的虚拟化,把整卡链路打磨到稳定、把平台资源模型定义清楚,再根据业务负载特征一步步引入共享和 vDCU,这条路走起来会顺畅很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 4:34:23

2025系统架构设计师备考全攻略:从核心知识到考场实战

系统架构设计师&#xff0c;软考高级资格里最热门、关注度最高的一个方向。我是在2025年上半年报的名&#xff0c;考完那天晚上我在备考群里看到一水的“案例题好难”“论文写偏了”&#xff0c;说实话当时心里也打鼓。但等成绩出来再回头看整个过程&#xff0c;我反而觉得这场…

作者头像 李华
网站建设 2026/9/12 4:34:19

基于Docker Compose与Caddy构建Nextcloud私有云盘,实现HTTPS自动配置

先说一句&#xff1a;Nextcloud这玩意儿&#xff0c;我前前后后折腾了不止三五次&#xff0c;最烦的不是功能配置&#xff0c;反而是装在容器里之后的网络和证书问题。但如果你从一开始就用docker-compose把服务编排好&#xff0c;再用Caddy做反向代理自动签HTTPS证书&#xff…

作者头像 李华
网站建设 2026/9/12 4:34:18

AI应用工程化交付:文档驱动控制模型不确定性的实践指南

AI 应用跑通 Demo 容易&#xff0c;真正难的是交付。做过 RAG 问答、Agent 编排这类项目的人应该都有同感&#xff1a;原型阶段一两天就能拉起来&#xff0c;可一旦进入工程化交付&#xff0c;需求边界乱、指标说不清、模型一换就崩、Prompt 调完没法回滚&#xff0c;项目越往后…

作者头像 李华
网站建设 2026/9/12 4:34:06

状态机原理与应用:从基础概念到工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:33:19

IntelliJ IDEA 轻量化实践:Spring Boot 开发环境性能优化指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:32:49

Rust构建高性能VSCode代码补全插件实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华