在容器内启用 RDMA 需要挂载哪些字符设备

解读

国内金融、电信、AI 训练等场景普遍用 RoCE v2InfiniBand 做高性能网络,容器要直通 RDMA 就必须把宿主机里的 字符设备节点 挂载到容器内部,否则即使加载了驱动,用户态库(如 libibverbs)也打不开设备。面试时考官想确认两点:

  1. 你是否知道 RDMA 在 Linux 下暴露的是哪类设备;
  2. 你是否能区分 必须设备可选设备,并给出最小权限原则下的挂载方案,避免把整个 /dev 挂进去。

知识点

  1. RDMA 子系统统一使用 字符设备(major 231),每个端口对应一个 /dev/infiniband/uverbsX 节点。
  2. 老版本驱动还会创建 /dev/infiniband/rdma_cm/dev/infiniband/umadX/dev/infiniband/issmX,但 uverbsX 是 verbs 接口的唯一必备入口
  3. 容器运行时需同时满足:
    • --device 把宿主机对应 uverbsX 映射到容器同一路径;
    • --cap-add IPC_LOCK 允许注册大页内存;
    • --ulimit memlock=-1 解除锁内存上限;
    • 若用 RDMA_CM 事件通道,再追加 /dev/infiniband/rdma_cm
  4. 国内大厂生产规范要求 非特权容器,因此不能加 --privileged,只能精确挂载。

答案

最小化挂载只需 /dev/infiniband/uverbsX(X 对应要使用的 RDMA 端口编号)。
如果业务代码走 rdma_cm 做连接管理,再额外挂载 /dev/infiniband/rdma_cm
其余 umadX、issmX 属于诊断或 SM 代理场景,普通业务容器无需挂载。
Docker CLI 示例(假设使用端口 0):

docker run -it --device=/dev/infiniband/uverbs0 \
           --device=/dev/infiniband/rdma_cm \
           --cap-add IPC_LOCK \
           --ulimit memlock=-1 \
           my-rdma-image

拓展思考

  1. 多端口场景:宿主机有 uverbs0、uverbs1 时,可通过 --device 多次指定,也可在 docker-compose 里用 devices 列表统一声明。
  2. Kubernetes 落地:国内普遍使用 Device Plugin(如 RDMA Device PluginMellanox k8s-rdma-shared-dev-plugin)把 uverbs 注册成 extended resource,然后在 pod spec 里申请 rdma/hca: 1,避免手工写 hostPath。
  3. 安全加固
    • 给容器单独分配 SELinux 标签AppArmor 模板,禁止访问非 RDMA 字符设备;
    • 使用 --group-add 39(宿主机 rdma 组 GID)确保容器内进程拥有 /dev/infiniband 的读写权限,而不是 root。
  4. 驱动版本差异:CentOS 7 自带 mlx5_core 可能只创建 uverbs0,而 MLNX_OFED 5.x 会额外生成 /dev/infiniband/rdma_cm,上线前务必 ls -l /dev/infiniband 确认,避免镜像迁移后缺失设备导致 ibv_get_device_list 返回空列表。