在容器内启用 RDMA 需要挂载哪些字符设备
解读
国内金融、电信、AI 训练等场景普遍用 RoCE v2 或 InfiniBand 做高性能网络,容器要直通 RDMA 就必须把宿主机里的 字符设备节点 挂载到容器内部,否则即使加载了驱动,用户态库(如 libibverbs)也打不开设备。面试时考官想确认两点:
- 你是否知道 RDMA 在 Linux 下暴露的是哪类设备;
- 你是否能区分 必须设备 与 可选设备,并给出最小权限原则下的挂载方案,避免把整个 /dev 挂进去。
知识点
- RDMA 子系统统一使用 字符设备(major 231),每个端口对应一个 /dev/infiniband/uverbsX 节点。
- 老版本驱动还会创建 /dev/infiniband/rdma_cm、/dev/infiniband/umadX、/dev/infiniband/issmX,但 uverbsX 是 verbs 接口的唯一必备入口。
- 容器运行时需同时满足:
- --device 把宿主机对应 uverbsX 映射到容器同一路径;
- --cap-add IPC_LOCK 允许注册大页内存;
- --ulimit memlock=-1 解除锁内存上限;
- 若用 RDMA_CM 事件通道,再追加 /dev/infiniband/rdma_cm。
- 国内大厂生产规范要求 非特权容器,因此不能加
--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
拓展思考
- 多端口场景:宿主机有 uverbs0、uverbs1 时,可通过 --device 多次指定,也可在 docker-compose 里用 devices 列表统一声明。
- Kubernetes 落地:国内普遍使用 Device Plugin(如 RDMA Device Plugin 或 Mellanox k8s-rdma-shared-dev-plugin)把 uverbs 注册成 extended resource,然后在 pod spec 里申请 rdma/hca: 1,避免手工写 hostPath。
- 安全加固:
- 给容器单独分配 SELinux 标签 或 AppArmor 模板,禁止访问非 RDMA 字符设备;
- 使用 --group-add 39(宿主机 rdma 组 GID)确保容器内进程拥有 /dev/infiniband 的读写权限,而不是 root。
- 驱动版本差异:CentOS 7 自带 mlx5_core 可能只创建 uverbs0,而 MLNX_OFED 5.x 会额外生成 /dev/infiniband/rdma_cm,上线前务必 ls -l /dev/infiniband 确认,避免镜像迁移后缺失设备导致 ibv_get_device_list 返回空列表。