作者:昇腾实战派

背景概述

Kubernetes原生设计聚焦于CPU、内存等通用计算资源,但无法直接管理GPU、FPGA、高性能网络等异构硬件设备。为解决这一问题,Kubernetes引入设备插件(Device Plugin)机制,允许设备厂商通过标准化接口向集群注册设备信息,实现设备发现、健康监控与资源调度。本文聚焦NPU(神经网络处理单元)设备插件的实现方案,阐述其如何通过Kubernetes设备插件规范,将NPU资源纳入集群统一管理,为AI工作负载提供高效资源调度能力。

1. 设备插件核心功能

1.1 设备发现

设备插件通过调用底层硬件管理接口(如DCMI),自动发现节点上的NPU设备数量与拓扑信息,并将设备信息上报至Kubernetes。上报内容包括:

  • 芯片型号(如NPU 910)
  • 设备ID(物理标识)
  • 资源数量(如huawei.com/NPU910: 8
  • 设备健康状态

1.2 健康检查

插件周期性检测NPU设备状态(温度、故障率等),当设备异常时:

  • 立即标记设备为Unhealthy
  • 通过Kubernetes API上报状态变更
  • 自动从资源池中移除故障设备,避免调度到异常节点

1.3 设备分配

当Kubernetes调度器分配NPU资源时,插件通过Allocate接口完成:

  • 为容器分配指定数量的NPU资源
  • 生成挂载路径与环境变量(如NPU_DEVICE_ID
  • 传递HCCL通信拓扑文件路径
  • 确保容器内应用可直接访问NPU设备

2. 工作原理

2.1 核心机制

Kubernetes设备插件遵循标准gRPC接口规范,实现三个关键方法:

接口方法 功能描述
Register 插件启动时向Kubelet注册资源类型(如huawei.com/NPU910
ListAndWatch 周期性上报设备列表(默认5秒间隔),包含设备ID、状态、数量
Allocate 根据调度请求分配设备,返回挂载路径与环境变量

2.2 通信流程

  1. 启动注册:插件启动后创建Unix Socket(如/var/lib/kubelet/device-plugins/NPU910.sock),向Kubelet注册
  2. 设备上报:插件通过DCMI接口获取设备信息,周期性调用ListAndWatch上报
  3. 资源分配:Kubelet收到调度请求后,调用Allocate分配设备
  4. 容器挂载:插件返回挂载路径,容器启动时自动挂载NPU设备
    k8s设备插件注册流程

3. 关键特性

3.1 资源管理能力

能力 中心侧支持 边缘侧支持 说明
静态算力切分 按固定比例切分芯片资源
动态算力切分 运行时按需切分(如1/2/4/8核)
设备故障重调度 故障设备自动从资源池移除
网络故障重调度 依赖Volcano调度器实现
推理热复位 异常设备重启恢复(NPU 310系列)

:动态算力切分场景下,插件将单颗NPU芯片(如NPU 310P)虚拟化为多个逻辑设备(如npu-core0~npu-core7),用户通过npu-core数量指定资源需求。

3.2 部署与兼容性

  • 部署方式:以DaemonSet形式部署,确保每个节点运行一个实例
  • 权限要求
    • 需挂载/var/lib/kubelet/device-plugins目录
    • 必须以特权模式运行(privileged: true
  • 硬件兼容性
    • 中心侧:支持NPU 910、NPU 310P(含动态切分)
    • 边缘侧:支持NPU 310(静态切分)、边缘设备(如Atlas 500)

3.3 故障处理机制

当NPU设备异常时:

  1. 插件检测到健康状态变为Unhealthy
  2. 立即上报Kubernetes,触发资源池更新
  3. 若集成Volcano调度器,自动将任务迁移至健康节点
  4. 故障设备恢复后,自动重新加入资源池

关键设计:热复位操作仅在设备空闲时执行,避免任务中断。复位耗时约15-24秒(NPU 310系列)。

4. 代码实现关键点

4.1 服务注册与通信

// pkg/server/server.go
func StartServer() error {
    // 验证Kubelet socket权限
    if err := common.VerifyPathAndPermission(); err != nil {
        return err
    }
    // 建立gRPC连接
    conn, err := grpc.Dial(kubeletSocket, grpc.WithInsecure(), grpc.WithContextDialer(...))
    if err != nil { /* 错误处理 */ }
    // 向Kubelet注册插件
    client := deviceplugin.NewDevicePluginClient(conn)
    if _, err := client.Register(context.Background(), &RegisterRequest{...}); err != nil {
        return err
    }
    return nil
}

4.2 设备状态监控

// pkg/server/plugin.go
func (p *plugin) ListAndWatch(r *ListAndWatchRequest, stream DevicePlugin_ListAndWatchServer) error {
    for {
        // 获取设备状态(DCMI接口)
        devices, err := p.getNpuDevices()
        if err != nil { /* 重试逻辑 */ }
        // 上报设备列表
        if err := stream.Send(&ListAndWatchResponse{Devices: devices}); err != nil {
            return err
        }
        time.Sleep(5 * time.Second) // 周期性上报
    }
}

4.3 动态算力切分分配

// pkg/server/plugin.go
func (p *plugin) Allocate(ctx context.Context, req *AllocateRequest) (*AllocateResponse, error) {
    // 1. 解析请求的npu-core数量
    coreCount := req.GetContainerRequests()[0].GetResources().GetNpuCore()
    // 2. 从可用设备中分配
    deviceID := p.allocateDevice(coreCount)
    // 3. 返回挂载路径与环境变量
    return &AllocateResponse{
        ContainerResponses: []*ContainerAllocateResponse{
            {
                Envs: map[string]string{
                    "NPU_DEVICE_ID": deviceID,
                    "HCCL_TOPO_FILE": "/etc/hccl/topo.json",
                },
                Mounts: []*Mount{
                    {HostPath: "/dev/davinci0", ContainerPath: "/dev/davinci0"},
                },
            },
        },
    }, nil
}

5. 部署约束与最佳实践

5.1 关键约束

约束类型 说明
NPU驱动 升级驱动前需停止设备插件服务,避免驱动冲突
与容器运行时配合 需优先安装兼容的容器运行时(如Ascend Docker Runtime v5.0.RC1+)
DCMI动态库权限 父目录需属主为root,且无group/other写权限(路径深度<20)
虚拟机环境 需在镜像中预装systemd(apt-get install -y systemd

5.2 部署示例(DaemonSet)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: npu-device-plugin
spec:
  selector:
    matchLabels:
      name: npu-device-plugin
  template:
    metadata:
      labels:
        name: npu-device-plugin
    spec:
      containers:
      - name: npu-device-plugin
        image: npu-device-plugin:latest
        securityContext:
          privileged: true
        volumeMounts:
        - name: device-plugin
          mountPath: /var/lib/kubelet/device-plugins
      volumes:
      - name: device-plugin
        hostPath:
          path: /var/lib/kubelet/device-plugins
          type: DirectoryOrCreate

6. 扩展能力

6.1 拓扑文件生成

插件支持动态生成HCCL通信拓扑文件,确保分布式训练任务正确建立通信链路:

  • 通过DCMI接口获取NPU物理拓扑
  • 生成符合HCCL要求的ranktabletopo.json
  • 自动注入容器环境变量HCCL_TOPO_FILE

6.2 与Volcano调度器集成

  • 核心价值:实现故障自愈与亲和性调度
  • 工作流程
    1. Volcano调度器根据设备状态选择节点
    2. 插件在Allocate阶段写入设备映射关系
    3. 故障发生时,Volcano自动迁移任务至健康节点
    4. 插件完成设备热复位后重新加入资源池

:动态算力切分场景下,插件需与Volcano协同维护设备映射表,确保并发分配时资源不冲突。


技术价值总结:通过标准化设备插件机制,NPU资源管理实现与Kubernetes原生调度器的深度集成。开发者无需修改应用代码,即可通过声明式资源请求(如resources: {huawei.com/NPU910: 2})获取NPU资源,同时享受故障自愈、动态切分等高级能力,显著提升AI工作负载的资源利用率与系统可靠性。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐