已关闭
[RFC]: k8s-rdma-shared-dev-plugin 支持华为昇腾 UB RDMA 共享模式 #223
lirui2381创建于  4月27日关闭于  9月8日
lirui2381
lirui2381成员
4月27日 创建

k8s-rdma-shared-dev-plugin 设计文档(华为昇腾 UB RDMA 共享模式)

版本 日期 作者 变更说明
v1.0 2026-04-27 刘云程(yuncliu)、李睿(lirui2381) 初始版本,支持 HCA 共享模式及 Volcano 基础集成
— 待定 — 未来增加高级调度特性

目录


1. 引言

1.1 背景

在大语言模型(LLM)和高性能计算(HPC)领域,分布式训练任务需要节点间频繁交换数 GB 级别的梯度数据。传统的 TCP/IP 协议栈由于存在内存拷贝和内核态/用户态上下文切换的开销,已成为制约集群计算效率的关键瓶颈。

RDMA(Remote Direct Memory Access,远程直接内存访问)技术允许网卡直接读写对端内存,绕过操作系统内核,实现零拷贝数据传输。在 Kubernetes 环境中,如何将宿主机上的 RDMA 设备安全、高效地提供给容器(Pod)使用,是构建 AI 基础设施的核心挑战。RDMA Shared Device Plugin 正是解决这一问题的关键组件。

1.2 问题描述

在未部署 RDMA 设备插件之前,Kubernetes 集群面临以下问题:

  • 资源不可见:Kubelet 无法感知宿主机上的 UB RDMA 设备,因此无法将其作为可调度资源进行管理。
  • 资源无法分配:Pod 无法在 resources.limits 中声明对 RDMA 设备的需求,调度器无法基于 UB RDMA 资源容量进行节点选择。
  • 设备无法挂载:即使 Pod 被调度到拥有 RDMA 设备的节点,容器运行时也不知道应将哪些设备文件(如 /dev/infiniband/uverbsX)挂载到容器内部。
  • 多 Pod 共享冲突:多个 Pod 若同时访问同一 UB RDMA 设备,可能导致资源竞争和数据损坏,缺乏有效的隔离机制。

RDMA Shared Device Plugin 旨在通过实现 Kubernetes Device Plugin 标准接口,系统性地解决上述问题。

1.3 术语与定义

本文档涉及的核心术语定义如下:

术语 定义
RDMA Remote Direct Memory Access,一种允许设备直接读写远程内存的技术,绕过操作系统内核。
HCA Host Channel Adapter,主机通道适配器,即支持 RDMA 的网卡硬件。
RoCE RDMA over Converged Ethernet,将 RDMA 报文封装在以太网帧中的技术。
InfiniBand (IB) 专为 RDMA 设计的专用网络架构。
Device Plugin Kubernetes 设备插件框架,通过 gRPC 接口将异构设备资源注入集群。
UB Unified Bus,华为自定义设备总线,用于昇腾 AI 处理器内部资源管理。
kubelet Kubernetes 节点代理,负责管理 Pod 生命周期和设备插件通信。

1.4 参考文献


2. 设计目标与约束

2.1 设计目标

  • 标准兼容:遵循 Kubernetes Device Plugin 规范,与现有 kubelet 无缝集成,无需修改 Kubernetes 核心代码。
  • 灵活配置:支持通过 ConfigMap 进行运行时配置,允许集群管理员根据实际需求定义资源名称、设备筛选规则和资源上限。
  • 节点级共享:将节点上所有 RDMA 设备作为一个整体资源池,Pod 获得全部设备的访问权限,最大化通信能力。
  • 可扩展性:设备筛选器支持厂商 ID、设备 ID、驱动名称、网络接口名称、总线类型等多维度匹配,易于扩展至新设备类型。
  • 任务故障自愈:Device Plugin 实时将 HCA 健康状态写入 DP的ConfigMap的 "huawei.com/Ascend910-DPUUnhealthy"中;ascend-volcano 插件读取 ConfigMap,在调度时过滤含不健康 HCA 的节点,并在节点出现故障时触发 Pod 重调度。

2.3 设计约束

  • 宿主机依赖:宿主机已安装 RDMA 驱动,并加载 ib_uverbs、ib_core 等内核模块。
  • 特权要求:插件容器需要访问宿主机的 /sys 文件系统以及 /var/lib/kubelet/device-plugins 目录。

3. 总体架构设计

3.1 架构图

graph TB
    subgraph ControlPlane[Kubernetes Control Plane]
        API[API Server]
        Sched[Scheduler / Volcano]
        etcd[(etcd)]
    end

    subgraph WorkerNode[Worker Node]
        Kubelet[kubelet]
        Plugin[RDMA Device Plugin<br/>DaemonSet]
        Config[ConfigMap<br/>config.json]
        Kernel[Linux Kernel]
        RDMA_NIC[RDMA Capable NICs<br/>/sys/class/infiniband/rocep*]
    end

    API -- Watch/Update --> Sched
    Sched -- Bind --> API
    Kubelet -- gRPC Register/ListAndWatch --> Plugin
    Plugin -- Read --> Config
    Plugin -- sysfs discover --> Kernel
    Kernel --> RDMA_NIC
    Plugin -- gRPC Allocate --> Kubelet
    Kubelet -- CRI --> ContainerRuntime
    ContainerRuntime --> Pod

3.2 组件协作

RDMA Shared Device Plugin 以 DaemonSet 形式部署在每个节点上,主要与以下 Kubernetes 组件交互:

  • kubelet(Device Manager):通过 Unix Domain Socket 进行 gRPC 通信,实现设备注册、心跳上报和资源分配。
  • ConfigMap:挂载到插件容器内,用于读取设备发现的过滤规则和资源名称配置。
  • 宿主机 sysfs:插件通过扫描 PCI 总线及 UB 总线进行 RDMA 设备发现。

3.3 与 Kubernetes 设备插件框架的关系

插件完整实现 Device Plugin 框架定义的 gRPC 接口:

  • Registration:插件启动后向 kubelet 的注册服务器发起注册请求。
  • ListAndWatch:注册成功后,kubelet 调用此接口获取设备列表,并持续监听设备状态变化。
  • Allocate:当 Pod 请求 RDMA 资源时,kubelet 调用此接口获取需要挂载的设备文件路径和环境变量。

4. 核心模块设计

📌 说明:第 4 章、第 5 章、第 6 章描述的是开源 k8s-rdma-shared-dev-plugin 的通用设计与实现逻辑。华为昇腾 UB 设备的差异化适配(设备发现扩展、UB 总线扫描、自定义筛选器等)请参见第 7 章。

4.1 设备发现模块

插件通过扫描 PCI 总线 上的网络设备作为发现起点,。具体流程分为三个阶段:

阶段一:锁定 PCI 网络设备

扫描 /sys/bus/pci/devices/ 下所有 PCI 设备,过滤出 PCI 类代码为 0x02 的设备(即网络控制器)。这一步从硬件层面捕获所有可能的网络设备。

阶段二:通过 selectors 筛选

对阶段一发现的设备,读取其 PCI 配置空间属性(如 vendor、device、subsystem_vendor 等),并根据 ConfigMap 中定义的 selectors 进行过滤。支持的筛选条件包括:

  • vendors:厂商 ID
  • deviceIDs:设备 ID
  • drivers:驱动名称
  • ifNames:网络接口名称
  • linkTypes:链路类型(ether 或 ib)

只有满足所有 selectors 条件的设备才进入下一阶段。

阶段三:确认 RDMA 能力

对于通过筛选的设备,插件检查 /sys/bus/pci/devices/<pci-addr>/net/<iface>/device/infiniband/ 目录是否存在且非空。若存在,则认为该设备具备 RDMA 能力,将其作为可分配的 HCA 设备加入资源池。

说明:ifNames 选择器依赖于设备在 /sys/class/net/ 下关联的网络接口名,但发现过程的起点仍是 PCI 总线设备。

4.2 设备上报模块 (ListAndWatch)

ListAndWatch 是 Device Plugin 框架中的核心 gRPC 流式接口,其设计要点如下:

  • 初始上报:建立连接后立即返回当前所有可分配的 RDMA 设备列表,每个设备由唯一的 DeviceID 标识。
  • 状态同步:通过 gRPC 流持续向 kubelet 发送设备状态更新。若设备健康,状态为 Healthy;若设备故障,状态变更为 Unhealthy,kubelet 将停止向该设备调度新 Pod。
  • 周期性刷新:插件内部维护一个后台 goroutine,按照 periodicUpdateInterval(默认 60 秒)定期调用 DiscoverHostDevices,检测设备变化并通过 ListAndWatch 流推送更新。
  • 心跳超时保护:ListAndWatch 流连接异常中断时,插件应重新发起注册流程。

4.3 资源分配模块 (Allocate)

当 Pod 被调度到节点并请求 RDMA 资源时,kubelet 调用 Allocate gRPC 接口。插件返回的 AllocateResponse 包含以下内容:

字段 说明 示例
Devices 需要挂载的设备文件列表。 /dev/infiniband/uverbs0, /dev/infiniband/uverbs1, … , /dev/infiniband/rdma_cm
Mounts 额外的文件系统挂载点(如大页内存)。 /dev/hugepages → /dev/hugepages

共享模式说明:插件在 Allocate 响应中返回 节点上所有可用 RDMA 设备 对应的字符设备路径,而非仅分配给 Pod 某个子集。每个 Pod 因此能够访问节点上的全部 HCA 设备。

4.4 配置管理模块 (ConfigMap)

插件通过挂载的 ConfigMap 进行动态配置,支持多资源配置。ConfigMap 的典型结构如下:

{
  "periodicUpdateInterval": 300,
  "configList": [
    {
      "resourceName": "rdma_shared",
      "resourcePrefix": "huawei.com",
      "rdmaHcaMax": 8,
      "selectors": {
        "vendors": ["19e5"],
        "ifNames": ["enp23s0f0", "enp23s0f1"]
      }
    }
  ]
}

字段说明:

字段 类型 必填 说明
periodicUpdateInterval int 否 周期性设备刷新间隔(秒),默认 60。
configList array 是 资源配置列表,支持同时暴露多个不同名称的 RDMA 资源。
configList[].resourceName string 是 扩展资源名称,Pod 通过 resources.limits.<resourceName> 申请。
configList[].resourcePrefix string 否 扩展资源的域名前缀,与 resourceName 拼接后作为完整资源名。
configList[].rdmaHcaMax int 是 该资源最大上报实例数。
configList[].selectors object 否 设备筛选器,支持 vendors、deviceIDs、drivers、ifNames、linkTypes、buses 等。
configList[].devices array 否 设备名称列表的显式白名单。

4.5 健康检查与周期性更新

  • 初始健康状态:设备发现时,通过检查 RDMA 设备端口状态(/sys/class/infiniband/<device>/ports/1/state)判定设备是否为 Healthy(PORT_ACTIVE 表示正常)。
  • 周期性健康探测:在 periodicUpdateInterval 间隔内重新扫描设备状态并更新缓存,通过 ListAndWatch 流推送变化。
  • 故障处理:设备标记为 Unhealthy 后,kubelet 停止向该设备调度新 Pod;恢复后重新加入可分配池。

4.6 资源模型:节点级共享

本插件采用 共享模式(Shared HCA Mode),将节点上所有可用的 RDMA 设备作为一个整体资源池。当 Pod 请求 huawei.com/rdma_shared 资源时:

  • 调度器仅检查节点上该资源的总剩余数量是否满足 Pod 请求(通常请求 1,表示 1 份额)。
  • Pod 被调度到节点后,插件在 Allocate 响应中返回节点上所有 RDMA 设备对应的字符设备路径。
  • 每个 Pod 都能访问该节点的全部 RDMA 硬件,实现最大化的设备共享与通信能力。

此模型适用于 AI 训练任务中需要跨 HCA 进行通信的场景,简化了调度逻辑。


5. 工作流程

5.1 插件启动与注册流程

  1. Pod 创建:通过 DaemonSet 控制器在集群节点上创建插件 Pod。
  2. 配置加载:插件启动后,从挂载的 ConfigMap 读取配置信息。
  3. gRPC 服务启动:插件为每个配置的资源创建一个 gRPC 服务端,监听 Unix Socket。
  4. 向 kubelet 注册:插件主动连接 kubelet 的 kubelet.sock,发送 Register 请求。
  5. 设备上报:注册成功后,kubelet 调用插件的 ListAndWatch 接口,插件开始向 kubelet 持续推送设备状态。

5.2 Pod 调度与设备分配流程

sequenceDiagram
    participant P as RDMA Plugin
    participant K as Kubelet
    participant S as Scheduler / Volcano
    participant API as API Server
    participant C as Container Runtime
    participant Pod as Pod

    P->>P: 启动 / 周期性扫描 sysfs
    P->>K: Register (gRPC)
    K->>P: ListAndWatch 流建立
    loop 心跳/状态更新
        P-->>K: 设备列表 + 健康状态
    end

    Note over S,API: Pod 创建 (schedule: volcano)
    S->>API: 绑定节点 (基于资源过滤)
    API->>K: 通知 Pod 分配
    K->>P: Allocate(deviceIDs)
    P-->>K: AllocateResponse<br/>(返回节点全部 HCA 设备文件)
    K->>C: CreateContainer (CRI)
    C->>Pod: 挂载 /dev/infiniband/* (全部)
    Pod->>Pod: 应用使用所有 RDMA 设备

5.3 设备故障处理流程

  1. 故障检测:插件在周期性健康检查中检测到设备状态异常。
  2. 状态更新:插件通过 ListAndWatch 流发送更新,将该设备标记为 Unhealthy。
  3. kubelet 响应:kubelet 将该节点上该资源的可分配数量减去故障设备数,停止向该设备调度新 Pod。
  4. 恢复处理:若设备恢复健康,插件将状态更新为 Healthy,kubelet 重新将其加入可分配池。

5.4 基于 ConfigMap 的 HCA 健康感知调度与故障重调度

节点上的 HCA 健康状态通过 ConfigMap 暴露,由ascend-volcano 插件(作为 Volcano 调度器的一个插件)负责读取并用于调度决策和故障重调度。

节点预选过滤(Predicate):在调度 Pod 时,读取所有节点的健康 ConfigMap。若节点存在任一不健康 HCA,则将该节点从候选列表中过滤掉,即使其 Allocatable 资源仍有剩余。

通过 Watch 机制监听 ConfigMap 的变化。当某个节点的健康状态从全部健康变为部分不健康时,插件需要识别出运行在该节点上的、请求了 huawei.com/rdma_shared 资源的 Pod,并触发其驱逐与重调度。

6. 配置模型

6.1 ConfigMap 配置结构

插件使用的 ConfigMap 挂载至容器内的 /k8s-rdma-shared-dev-plugin/config.json 路径。一个典型的完整配置示例如下:

{
  "periodicUpdateInterval": 300,
  "configList": [
    {
      "resourceName": "rdma_shared",
      "resourcePrefix": "huawei.com",
      "rdmaHcaMax": 8,
      "selectors": {
        "vendors": ["19e5"],
        "ifNames": ["enp23s0f0", "enp23s0f1"]
      }
    }
  ]
}

rdmaHcaMax 是用来控制节点上能并发运行多少个共享模式 Pod 的“总票数”,不是 Pod 内挂载的设备数量,应该设置为HCA设备的数量。

6.2 设备选择器 (Selectors)

插件支持的设备筛选机制(标准字段及扩展字段):

Selector 字段 类型 说明 示例
vendors []string 厂商 ID(PCI Vendor ID)。 ["19e5"](华为)
deviceIDs []string 设备 ID(PCI Device ID)。 ["0222"]
drivers []string 驱动名称。 ["hns"], ["mlx5_core"]
ifNames []string 网络接口名称。 ["enp23s0f0"]
linkTypes []string 链路类型。 ["ether"], ["ib"]
buses (扩展) []string 总线类型。为支持华为 UB 总线扩展。 ["pci"], ["ub"]

标准插件不包含 buses 字段,此为本方案为适配 UB 总线的扩展。若不配置则与社区兼容,扫描pci设备。若配置多个,如["pci","ub"]则报错退出。


7. 华为昇腾 UB RDMA 适配方案

7.1 背景说明

华为昇腾 UB 设备 不在 PCI 总线上,而是通过自定义的 /sys/bus/ub/devices/ 暴露。标准插件发现逻辑完全基于 PCI 总线扫描,因此无法原生识别 UB 设备。本章描述如何扩展插件以支持 UB 总线上的 RDMA 设备。

7.2 标准插件发现流程 vs. UB 设备发现需求

步骤 标准插件行为 UB 设备所需行为
1. 总线扫描 扫描 /sys/bus/pci/devices/ 扫描 /sys/bus/ub/devices/。
2. 属性读取 从 PCI 配置空间读取 vendor, device 等 从 UB 配置空间读取 vendor, device 等。vendor为cc08,device为8200。
3. 网络接口关联 通过 /sys/bus/pci/devices/{addr}/net/ 获取 ifNames,比如/sys/bus/pci/devices/0000:17:00.0/net/ UB 设备目录下也可能存在 net/ 子目录,插件需能遍历。
4. RDMA 确认 检查 /sys/class/net/{iface}/device/infiniband/,比如/sys/class/net/enp23s0f0/device/infiniband/ 检查 /sys/bus/ub/devices/{id}/infiniband/ 或通过 net/ 间接关联。

7.3 发现逻辑修改方案

在插件源代码中,修改 DiscoverHostDevices() 函数,增加对 UB 总线的扫描分支(伪代码):

func DiscoverHostDevices() []*HostDevice {
    devices := []*HostDevice{}
    // 原有 PCI 扫描
    for _, pciDev := range scanPCIDevices() {
        if isNetClass(pciDev) {
            devices = append(devices, pciDev)
        }
    }
    // 新增 UB 扫描 (如果配置允许)
    if ubScanEnabled() {
        for _, ubDev := range scanUBDevices() {
            // 1. 判断是否为网络/RDMA设备:检查是否存在 net/ 子目录,或 type 字段符合预期
            if isUBNetDevice(ubDev) {
                // 2. 补充属性供 selectors 匹配:读取 ubDev 下的 vendor, device 文件(若存在)
                //    否则设置默认 vendor=0x19e5
                // 3. 关联 RDMA: 检查 ubDev/infiniband/ 或 ubDev/net/*/device/infiniband/
                if hasRDMA(ubDev) {
                    devices = append(devices, ubDev)
                }
            }
        }
    }
    return devices
}

7.4 UB 设备筛选器扩展

在 ConfigMap 的 selectors 中增加以下字段以便精确筛选:

字段 类型 说明
buses []string 指定扫描设备类型为["ub"]
vendors []string 指定厂商ID为 ["cc08"]。
deviceIDs []int 指定设备ID为["8200"]根据 。

示例配置(仅筛选 UB 设备且 type=0x1):

{
  "configList": [
    {
      "resourceName": "ub_rdma",
      "resourcePrefix": "huawei.com",
      "selectors": {
        "buses": ["ub"], 
        "vendors": ["cc08"],
        "deviceIDs": ["8200"]

      }
    }
  ]
}

7.5 Allocate 阶段适配

对于 UB 设备,Allocate 返回的 DeviceSpec 与 PCI 设备相同,仍为 /dev/infiniband/uverbsX 及 /dev/infiniband/rdma_cm。若华为驱动需要额外设备节点(如 /dev/hns_*),可在 Allocate 响应中追加。


8. 安全与隔离

8.1 设备文件权限控制

插件在 Allocate 响应中返回的 DeviceSpec 指定了宿主机设备路径及容器内的访问权限(r、w、m)。容器运行时根据这些指令挂载设备文件。

建议的安全实践:

  • 为 RDMA 容器设置 securityContext.privileged: false,仅通过 capabilities 添加必要的 IPC_LOCK 权限。

8.2 网络命名空间隔离

Linux 的网络命名空间(netns)是实现 RDMA 设备隔离的核心机制。RDMA 子系统支持两种隔离模式:

模式 行为 适用场景
shared RDMA 设备全局可见,所有网络命名空间均可访问。 设备共享、资源利用率优先
exclusive RDMA 设备随其关联的网络接口一起移动至目标 netns。 严格隔离、安全要求高

本设计推荐使用 shared 模式,以支持节点级设备共享。


9. 部署与运维

9.1 DaemonSet 部署

插件以 DaemonSet 形式部署,YAML 关键配置:

  • hostNetwork: true:共享宿主机网络命名空间。
  • volumeMounts:挂载设备插件目录、sysfs 和 ConfigMap。
  • securityContext.privileged: true:需要特权访问硬件设备。

9.2 依赖条件

部署插件前,宿主机 MUST 满足以下条件:

  • 已加载 RDMA 内核模块(ib_uverbs、ib_core、对应网卡驱动如 hns)。
  • RDMA 设备已初始化且状态正常。
  • kubelet 已启动,且 /var/lib/kubelet/device-plugins 目录已存在。
# 验证 RDMA 设备就绪
ls /dev/infiniband/
ls /sys/class/infiniband/
ibv_devinfo

10. 未来演进

本设计文档的当前版本实现了 节点级共享模式 及 与 Volcano 调度器的基础集成。后续计划在以下方向继续演进:

  1. CDI (Container Device Interface) 集成:
    未来将引入 CDI 规范,实现设备注入的标准化。设备插件仅需返回 CDI 注解,实际挂载由容器运行时根据 CDI 规格文件完成。

附录 A:Pod 使用示例

以下是一个 Pod 申请 RDMA 资源的配置示例:

apiVersion: v1
kind: Pod
metadata:
  name: rdma-training-pod
spec:
  schedulerName: volcano   # 可选,若使用 Volcano 基础调度
  containers:
  - name: trainer
    image: my-rdma-app:latest
    resources:
      limits:
        huawei.com/rdma_shared: 1   # 请求 1 份额,实际获得节点上全部 HCA
    securityContext:
      capabilities:
        add: ["IPC_LOCK"]
    volumeMounts:
    - name: devshm
      mountPath: /dev/shm
  volumes:
  - name: devshm
    emptyDir:
      medium: Memory

关键配置说明:IPC_LOCK capability 是 RDMA 应用调用 mlock 所必需的权限,缺少会导致 ibv_reg_mr 失败。Pod 启动后,容器内将看到 /dev/infiniband/uverbs0 ~ /dev/infiniband/uverbsN 以及 /dev/infiniband/rdma_cm 等所有 RDMA 设备文件。

附录 B:术语表

术语 定义
RDMA Remote Direct Memory Access,允许设备直接读写远程内存。
HCA Host Channel Adapter,主机通道适配器(RDMA 网卡)。
RoCE RDMA over Converged Ethernet,以太网承载的 RDMA 技术。
InfiniBand (IB) 专为 RDMA 设计的高性能网络架构。
UB Unified Bus,华为自定义设备总线。
Device Plugin Kubernetes 设备插件框架,暴露硬件资源。
Volcano Kubernetes 高性能批量调度器。
CDI Container Device Interface,容器设备接口规范。
kubelet Kubernetes 节点代理。
gRPC 插件与 kubelet 通信的底层协议。
netns Linux 网络命名空间。

likedislike
lirui2381lirui2381成员
4月27日 添加了label:rfc
lirui2381
lirui2381成员
4月27日 评论:

/label add triaged

likedislike
ascend-robotascend-robot成员
4月27日 添加了label:triaged
lirui2381lirui2381成员
4月27日 修改了issue 的描述
lirui2381lirui2381成员
4月27日 关联了里程碑:MindCluster 26.1.0
lirui2381lirui2381成员
4月27日 修改了issue 的描述
lirui2381lirui2381成员
4月27日 修改了issue 的描述
Atlas_zxp
Atlas_zxp成员
4月27日 评论:

/label add triaged

likedislike
lirui2381lirui2381成员
4月27日 修改了issue 的描述
lirui2381lirui2381成员
5月5日 修改了issue 的描述
lirui2381lirui2381成员
5月5日 修改了issue 的描述
lirui2381
lirui2381成员
5月7日 评论:

没有huawei-ctk,需要删除

likedislike
lirui2381
lirui2381成员
5月7日 评论:

MACVLAN 模式支持删除,它没有roce能力

likedislike
lirui2381
lirui2381成员
5月7日 评论:

huawei.com/rdma_shared需要指出本质是共享次数,不是真实挂载数量

likedislike
lirui2381
lirui2381成员
5月7日 评论:

补充测试点,业务场景可以使用perftest

likedislike
lirui2381
lirui2381成员
5月7日 评论:

hca的数量是否可配

likedislike
lirui2381lirui2381成员
5月8日 修改了issue 的描述
此处折叠了21条事件消息 查看更多
lirui2381lirui2381成员
9月8日 关闭了 issue