海光DCU接入Kubernetes与CubeStudio:从设备插件到vDCU虚拟化及DeepSeek推理实践
2026/9/17 5:14:19 网站建设 项目流程

今天聊一个我最近一直在折腾的问题:海光 DCU 怎么接入 Kubernetes,再统一放进 CubeStudio 里调度。公司里有一批海光 DCU 的机器,放了很久没人真正用起来,算法同事催着要跑 DeepSeek。DCU 本身兼容 HIP/ROCm 生态,跑主流推理框架没有太大障碍,但真正卡壳的地方在平台层:K8s 不认这张卡,CubeStudio 这类 AI 平台更不可能自动感知 DCU,得先做设备插件、扩展资源和虚拟化适配。这篇我按自己的实操顺序来写:先讲整卡接入,再讲两种 vDCU 虚拟化的原理和配置,然后是 CubeStudio 资源池怎么建,最后完整跑通一个 DeepSeek 推理服务。适合平台工程师、运维,以及想自己折腾异构算力调度的算法同学参考。

1. 为什么要把海光 DCU 接进 Kubernetes 和 CubeStudio

1.1 算力碎片化:真实存在的痛点

很多团队的算力池是怎么慢慢变成一锅粥的?最开始只有 NVIDIA GPU,大家用 nvidia-device-plugin 把卡接进 K8s,模型训练、推理都在这套体系里跑。后来因为成本、供货或者信创要求,机器里多了海光 DCU。DCU 算力不差,显存也够大,但算法同学一看调度平台里没有这个资源,就不会去用,于是卡一直闲着。

我这边的情况是:GPU 节点已经快排满了,DCU 节点利用率不到 5%。不是没人跑任务,是平台根本不暴露 DCU 资源。大家申请算力只能写“我要 2 卡 GPU”,DCU 再强也无感知。这种算力碎片化问题,靠人肉调度解决不长久,必须让 DCU 以标准资源的形式进入 K8s,再由 AI 平台统一暴露给用户。

1.2 CubeStudio 是什么,为什么选它

CubeStudio 本质上是跑在 Kubernetes 之上的一层 AI 研发平台,负责把底层算力封装成“资源池”,给用户提供数据集、Notebook、训练任务、模型推理等能力。它自己不会去认 DCU 的物理设备,而是依赖 K8s 的扩展资源机制:只要节点上出现了hygon.com/dcu这类资源,平台就能把它纳入资源池,用户提交任务时就能按“几张卡、多少显存”来申请。

选择 CubeStudio 的原因很直接:我们内部已经在用它管 GPU 任务,算法同学对这套操作界面很熟。如果 DCU 能通过同一套 K8s 资源模型暴露出去,用户侧完全无感知,不需要学新工具。这也是我这次适配的核心思路:不改造平台本身,只补设备层和调度层的能力。

1.3 接入前先想清楚:整卡、共享、虚拟化的边界

在动手之前,得先把三种使用方式的分界线理清楚,不然后面配置时会很混乱。

  • 整卡模式:一个任务独占一张物理 DCU。优点是简单、稳定、性能最好,适合大模型训练、大尺寸推理。缺点是卡一旦分配出去,哪怕任务只用了一半显存,别人也用不了剩下的。
  • 共享模式:多个任务共用一张物理卡。适合开发调试、小模型推理、批量离线任务,能明显提高卡的整体利用率。
  • vDCU 虚拟化:共享的底层实现方式,一般分两种,一种是显存隔离型,一种是时间片复用型。这两种不是互斥的替代品,而是针对不同场景设计的调度手段。

先明白边界,后面选型的时候才不会纠结。

2. DCU 接入 K8s 的资源模型与设备插件

2.1 K8s 是怎么识别 DCU 的

K8s 原生不认识 GPU,也不认识 DCU。它只认识两类东西:CPU 和内存。要让集群感知到 DCU,标准做法是使用Extended Resource(扩展资源)Device Plugin(设备插件)

设备插件以 DaemonSet 方式跑在每个 DCU 节点上,启动时把节点上的 DCU 设备数量上报给 kubelet。kubelet 再把资源信息同步到 API Server,最终在kubectl describe node里看到类似:

Allocatable: cpu: 32 memory: 251Gi hygon.com/dcu: 4

用户提交 Pod 时,在resources.limits里声明hygon.com/dcu: 1,调度器就知道这个 Pod 需要一张 DCU,把它调度到有足够 DCU 资源的节点上。之后设备插件会在容器启动前,把对应的设备节点和环境变量注入容器,任务就能在容器里直接调用 DCU。

这套机制的重点是:DCU 的驱动要装好,设备节点要能被设备插件发现,设备插件上报的资源名要和 Pod 请求的资源名一致。任何一环对不上,任务都起不来。

2.2 整卡模式:最稳妥的第一步

整卡模式是所有适配工作的起点。我的建议是,任何团队接入 DCU,先别搞虚拟化,先把整卡链路跑通。

整卡模式的资源声明非常简单:

resources: limits: hygon.com/dcu: 1

不需要额外配置显存大小,也不需要关心卡内切分,一张卡就是最小调度单位。容器启动后,设备插件会设置HIP_VISIBLE_DEVICES之类的环境变量,应用只需要正常使用 HIP/ROCm 接口,就能看到对应的 DCU。

第一次验证时,可以跑一个最小的测试镜像,在容器里执行dcu-smi

dcu-smi

如果能看到卡的型号、显存、利用率,说明设备映射正常。这一步没通过,后面所有共享、vDCU 都不用谈。

2.3 共享模式的需求来源

整卡模式虽然稳,但利用率问题很真实。我这边很多算法同学跑的是数据处理、小模型微调、批量推理,显存占用往往只有几个 GB,却要整卡申请。一张 32GB 甚至 64GB 的 DCU,大部分时间在空转。

共享模式就是为这个场景设计的:把一张物理卡同时分配给多个任务。但共享不是白捡的,怎么共享、怎么隔离,决定了任务的稳定性和性能表现。这也是为什么要细究两种 vDCU 虚拟化方案。

2.4 第一种 vDCU:显存隔离型

显存隔离型 vDCU 的思路是把一张物理卡的显存切成若干份,每个 vDCU 独占固定大小的显存,计算单元也按一定方式隔离。你可以把它理解成物理卡里的“独立房间”,每个房间有固定的墙,房间之间互不打扰。

这种模式适合生产环境推理服务。比如一张 64GB 的卡,切成 4 个 16GB 的 vDCU,同时跑 4 个不同的推理服务,每个服务独占 16GB 显存,不会因为邻居任务吃满显存而 OOM。

配置时,资源请求通常长这样:

resources: limits: hygon.com/dcu-vmemory: 16

具体资源名不同版本可能不一样,但语义都是“给我一个 16GB 的 vDCU”。这种模式的优点是隔离性好、性能可预期;缺点是显存切分后,如果某个 vDCU 实际只用了一半显存,剩下的也无法给别的任务用,依然存在一定浪费。

2.5 第二种 vDCU:时间片复用型

时间片复用型的思路完全不同。它不切割显存,而是让多个 vDCU 共享整张卡的显存和计算单元,通过调度器按时间片或优先级在任务之间切换。可以理解成多个人共用一张办公桌,谁用的时候谁在位,但桌面上的东西是大家共用的。

这种模式最直观的好处是超卖。比如一张卡可以创建 8 个 vDCU,同时跑 8 个开发调试任务,每个任务实际占用的显存都不大,计算资源通过时间片轮转,整体利用率会非常高。

配置时,资源请求可能长这样:

resources: limits: hygon.com/dcu-vslice: 1

但风险也很明显:没有显存隔离,一个任务把显存吃满,会影响同卡上的所有其他任务。所以时间片复用型更合适开发环境、低优先级批任务、或者你完全清楚任务显存水位的情况。生产环境的推理服务,我一般不建议直接用时间片复用型。

2.6 两种 vDCU 的对比与选型

维度显存隔离型 vDCU时间片复用型 vDCU
显存隔离有,每个 vDCU 独占显存无,共享整卡显存
计算资源隔离较好,按分区或权重分配较弱,按时间片抢占
超卖能力基本不支持支持,可创建多个 vDCU
典型场景生产推理、稳定在线服务开发调试、批处理、低优任务
风险点显存切分后有浪费显存冲突、邻居干扰
调度精度高,可指定显存大小低,通常按数量申请

选型建议很简单:在线服务优先显存隔离,离线任务优先时间片复用,两者可以同时启用。比如一张卡切出 2 个 16GB 的显存隔离型 vDCU 跑线上推理,再开出 4 个时间片型 vDCU 给开发同学做实验,充分利用剩余算力。

3. CubeStudio 海光 DCU 适配实操

3.1 环境准备:驱动、DTK、容器运行时

实操第一步,把节点底子打好。海光 DCU 跑 HIP/ROCm 生态,依赖两个关键组件:内核驱动和 DTK(DCU Toolkit)。驱动装好后,系统里会出现对应的设备节点,通常是/dev/kfd/dev/dri/renderD*这类路径。用dcu-smi验证:

dcu-smi

正常输出会列出卡号、显存总量、驱动版本、温度、利用率等信息。

接着确认容器运行时能识别设备。K8s 的设备插件虽然会在容器启动时注入设备节点,但如果容器运行时的配置文件里限制了设备挂载,任务起不来。用 containerd 时,建议先把运行时的基础配置检查一遍,确保没有白名单限制/dev/kfd/dev/dri

另外建议把dcu-smi也做进基础镜像里,后面排查问题会省很多时间。

3.2 部署 DCU 设备插件

设备插件是接入 K8s 的核心组件。一般以 DaemonSet 方式部署,一个节点一个 Pod。以我这边为例,设备插件的主要配置包括资源名hygon.com/dcu,以及是否开启共享、选择哪种虚拟化模式。

部署后立刻检查两个东西:

kubectl get pod -n kube-system -o wide | grep dcu kubectl describe node <dcu-node>

期望结果是:插件 Pod 处于 Running 状态,节点描述里出现hygon.com/dcu的可分配数量,且数量和实际物理卡数量一致。

这一步常见的坑是插件 Pod 起来了,但节点不显示扩展资源。排查时优先看插件日志,八成是设备节点路径不对,或者权限不足读不到设备。

3.3 在 CubeStudio 里创建 DCU 资源池

设备插件把 DCU 上报到 K8s 后,CubeStudio 这边就相对简单了。在平台管理后台,找到资源池配置页面,新增一个 DCU 资源池。

关键配置点:

  • 节点选择器:给 DCU 节点打上标签,比如accelerator=hygon-dcu,资源池绑定这个标签,避免和 GPU 节点混在一起。
  • 资源类型:添加hygon.com/dcu,平台会读取节点上的可分配数量。
  • 配额策略:给不同项目组设置 DCU 配额,比如某个算法组默认可以申请 2 张整卡或 8 个 vDCU,配额用完了需要申请扩容。

配置完成后,用户在平台界面创建 Notebook 或推理服务时,就能在资源选择里看到 DCU 选项。这里我一直强调:平台侧不需要改代码,它只是把 K8s 的资源模型翻译成界面选项。所以前期设备层的适配越规范,平台侧就越省事。

3.4 跑通第一个整卡任务

资源池建好后,先别急着提交大任务,跑一个最小的整卡验证任务。

我在 CubeStudio 里创建了一个测试 Notebook,镜像里预装了 DTK 和dcu-smi,资源申请选择1张 DCU 整卡。启动后打开终端:

dcu-smi

能正常列卡,再跑一段 HIP 的向量计算代码,确认计算能力没问题。这一步的意义是验证从“平台界面”到“容器内部”的整条链路通了,后面再做 vDCU 才心里有底。

3.5 在 CubeStudio 里配置 vDCU 共享

共享能力一般在设备插件侧开启,然后在 CubeStudio 里把对应的 vDCU 资源类型暴露出来。

我这边开了两个共享模板:

  • 模板 A(显存隔离型):每张卡切成 4 个 16GB 的 vDCU,主要用于在线推理服务。
  • 模板 B(时间片复用型):每张卡创建 8 个 vDCU,数量可超卖,主要用于开发调试。

平台侧会把这两个模板映射成不同的资源请求。用户提交任务时,选了模板 A,后端生成的就是携带显存隔离型资源声明的 Pod;选了模板 B,后端生成的就是携带时间片型资源声明的 Pod。

这里必须提醒一句:虚拟化模式一定要和任务特征匹配。我有一次图省事,把一个线上推理服务跑在时间片复用型 vDCU 上,结果旁边开发同学的实验把显存吃满,线上服务直接 OOM,最后只能重启。后来所有生产推理服务统一走显存隔离型,再没出过这个问题。

4. DeepSeek 模型在 DCU 上跑通的全流程

4.1 模型选型与推理框架选择

DCU 接入平台和调度只是基础设施,最终还得看业务能不能跑起来。我们这次的目标是 DeepSeek。

DeepSeek 官方的大杯模型,比如 DeepSeek-R1 的 671B 版本,对显存和带宽的要求很高,一般团队没有多机多卡环境,不建议直接上。更实际的选择是蒸馏系列,比如DeepSeek-R1-Distill-Qwen-7B / 14B / 32B,模型尺寸适中,效果也不错,更适合在单机或双卡 DCU 节点上部署。

推理框架方面,vLLM 是目前兼容性最好、社区最活跃的选择之一。DCU 兼容 HIP/ROCm 生态,所以理论上只要 vLLM 能跑在 ROCm 环境,就能跑在 DCU 上。建议优先使用带 HIP 后端的 vLLM 镜像,或者直接用海光官方/厂商适配过的镜像,能少踩不少编译坑。

显存估算可以参考这个表:

模型精度显存估算
DeepSeek-R1-Distill-Qwen-7BFP16约 16GB
DeepSeek-R1-Distill-Qwen-14BFP16约 30GB
DeepSeek-R1-Distill-Qwen-32BFP16约 65GB
DeepSeek-R1-Distill-Qwen-32BINT8/INT4 量化20GB~35GB

我这边用的是 32B 版本,配合一张大显存的 DCU 整卡,效果和成本比较平衡。

4.2 构建推理镜像

镜像里需要包含 vLLM、DTK 运行库、dcu-smi工具,以及模型服务的启动脚本。Dockerfile 大致长这样:

FROM registry.example.com/dcu-base:latest RUN pip install vllm \ && pip install "transformers" "safetensors" "accelerate" ENV HIP_VISIBLE_DEVICES=0 WORKDIR /app CMD ["vllm", "serve", "/models/DeepSeek-R1-Distill-Qwen-32B", "--host", "0.0.0.0", "--port", "8000"]

模型文件建议直接挂载到容器目录,不要放在镜像里,不然镜像体积几个 GB 起步,构建和拉取都痛苦。

4.3 编写 Kubernetes 部署清单

最终跑在 K8s 上的 Deployment 长这样:

apiVersion: apps/v1 kind: Deployment metadata: name: deepseek-r1-32b namespace: ai-platform spec: replicas: 1 selector: matchLabels: app: deepseek-r1-32b template: metadata: labels: app: deepseek-r1-32b spec: nodeSelector: accelerator: hygon-dcu containers: - name: vllm image: registry.example.com/dcu-vllm:latest command: - vllm - serve - /models/DeepSeek-R1-Distill-Qwen-32B - --host - 0.0.0.0 - --port - 8000 - --gpu-memory-utilization - "0.9" - --max-model-len - "32768" ports: - containerPort: 8000 resources: limits: hygon.com/dcu: 1 volumeMounts: - name: model-storage mountPath: /models livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 600 periodSeconds: 60 volumes: - name: model-storage persistentVolumeClaim: claimName: deepseek-model-pvc

这里有两个细节要注意:

  • 资源声明用的是hygon.com/dcu: 1,也就是整卡模式。32B 模型需要完整显存,用整卡最稳。
  • livenessProbeinitialDelaySeconds要设大一点。vLLM 加载 32B 模型可能要几分钟,探针设太短会导致容器反复被重启。

如果部署 7B 模型,可以考虑使用显存隔离型 vDCU,比如申请一个 16GB 的 vDCU,多路复用一张物理卡,成本更低。

4.4 启动验证与并发调优

服务起来后,先看模型是否加载完成:

curl http://<pod-ip>:8000/v1/models

能返回模型列表,说明服务已经就绪。接着发一个对话请求:

curl http://<pod-ip>:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-r1-32b", "messages": [{"role": "user", "content": "用一句话介绍 Kubernetes"}], "max_tokens": 512 }'

正常返回文本后,观察 DCU 资源的使用情况:

dcu-smi

重点看显存利用率和计算利用率。如果显存已经吃满,计算利用率却很低,说明瓶颈在推理并发不够,可以调大--max-num-seqs;如果经常报显存不足,优先降低--max-model-len或调低--gpu-memory-utilization

5. 常见问题与排查实录

5.1 高频故障速查表

问题可能原因排查方法解决方案
节点不显示 hygon.com/dcu 资源设备插件没起来或上报失败kubectl logs -n kube-system <dcu-plugin-pod>检查驱动路径、设备节点权限
Pod 一直 Pending节点 DCU 资源不足kubectl describe pod <name>减少资源申请,或等任务释放
容器里看不到 DCU 设备设备插件未注入设备/环境变量检查 Pod YAML 里的环境变量重建设备插件,确认资源名一致
vLLM 启动报找不到 HIP 设备HIP_VISIBLE_DEVICES 未设置或 set 错误env查看容器环境变量手动指定设备和容器内实际设备号一致
共享模式下任务 OOM邻居任务占用显存查看 dcu-smi 显存水位换显存隔离型 vDCU
模型加载很慢权重文件从远端下载检查磁盘 I/O 和网络模型权重提前放本地 PVC 挂载
探针导致容器不断重启initialDelaySeconds 太短kubectl logs看启动日志调大延迟时间

5.2 我踩过的几个坑

第一个坑是设备插件版本和驱动不匹配。最开始我随便拉了一个插件版本,结果节点上报的卡数量只有实际的一半,排查了半天才发现是插件读取设备列表的接口变了。后来统一了驱动和插件版本,问题消失。

第二个坑是共享模式下资源声明写错。vDCU 的资源名和整卡的资源名不一样,我在一个测试任务里用了整卡资源名,却想申请半个 vDCU,结果调度器直接拒绝。排错时先看资源名对不对,再看配额够不够。

第三个坑是容器内执行dcu-smi报权限错误。设备节点没挂进去,插件虽然注入了部分设备,但/dev/kfd权限不够。解决办法是在设备插件的配置里把需要挂载的设备节点列全,而不是只依赖默认规则。

第四个坑是 vLLM 启动时现场下载模型权重。K8s 节点从 Hugging Face 下载几十 GB 权重,慢到怀疑人生。后来我把模型文件放到内网对象存储,再通过 PVC 挂载,启动时间从半小时降到两分钟。

5.3 调优心得

跑稳定之后,我做了几轮并发压测,有几个经验可以分享:

  • 推理服务的--gpu-memory-utilization不要直接拉满到 0.99,留一点余量给临时张量和调度开销,0.9 是比较稳的值。
  • 时间片复用型 vDCU 虽然能超卖,但一定要注意限制每个任务的最大显存占用。建议配合平台的资源限额功能,给共享任务设置显存上限。
  • 如果同一个模型要服务多个业务线,优先用显存隔离型 vDCU 隔离部署,而不是复用同一个 vLLM 实例。虽然多占一些显存,但故障爆炸半径小很多。

6. 写在最后的个人心得

这轮海光 DCU 接入做下来,我最深的体会是:先把整卡链路打稳,再谈虚拟化,不要一上来就追求共享。整卡模式是地基,设备插件、资源上报、容器映射这些环节全部验证通过之后,再做 vDCU 就是水到渠成的事情。反过来的话,一旦出了问题,你根本分不清是驱动问题、调度问题还是虚拟化隔离问题。

另一个体会是,DCU 的生态现在确实比想象中好。HIP 兼容让 vLLM 这类主流框架可以直接跑,模型加载和推理效果都能到生产可用的水平,但这套东西的坑都藏在细节里:资源命名、设备节点权限、镜像版本、模型挂载方式,每一项都需要实际踩过才知道。如果你也在折腾类似的事情,建议按这个顺序推进:驱动到dcu-smi能识别,插件上报节点资源,整卡任务跑通,再逐步上共享和 vDCU,最后才部署 DeepSeek 推理服务。

后面我计划把 DCU 的训练任务也接进 CubeStudio,比如 LoRA 微调、SFT 这类场景。等跑完再更新一篇。大家如果有更稳的 vDCU 参数或共享调度策略,欢迎一起交流。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询