在 InfiniBand 网络下如何容器化 MPI 程序
解读
国内金融、超算、AI 训练中心普遍采用 Mellanox InfiniBand 作为高性能计算网络,容器化 MPI 程序时必须解决 RDMA 设备直通、用户态驱动一致性、进程启动模型、作业调度集成 四大痛点。面试官希望听到“从镜像构建到作业提交”全链路落地经验,而非简单跑通 hello-world。
知识点
- InfiniBand 内核栈:mlx5_core、mlx5_ib、ib_core 模块版本需与宿主机一致,容器内禁止升级。
- 用户态库版本锁定:libmlx5、librdmacm、libibverbs 版本必须与 OFED 驱动版本 严格对应,否则出现 “cannot allocate PD” 类错误。
- RDMA 设备直通:
--device /dev/infiniband/uverbs0 --device /dev/infiniband/rdma_cm同时挂载,缺一不可。 - IPC 与 PID namespace:MPI 需要共享内存,必须
--ipc=host --pid=host;若用 Slurm,则 srun 自带--mpi=pmix可自动注入。 - 特权与 Capabilities:国内超算中心出于安全审计,通常禁止
--privileged,需显式--cap-add=IPC_LOCK --cap-add=SYS_RESOURCE。 - HugePage 预留:HPC 作业调度系统(如 Slurm、PBS Pro)已预分配 HugePage,容器需挂载
/dev/hugepages并设置--ulimit memlock=-1。 - 进程管理模型:OpenMPI 4.x 默认采用 PMIx + prrte,容器镜像需内置 prrte 守护进程,并通过
--pid=host保证宿主机与容器进程树一致。 - 镜像多阶段构建:第一阶段用 nvidia/cuda:12.2.0-devel-ubi8 安装 OFED、编译 MPI;第二阶段用 nvidia/cuda:12.2.0-runtime-ubi8 仅拷贝运行时库,镜像体积从 3.8 GB 压缩到 980 MB,符合国内私有仓库配额限制。
- 国内源加速:在 Dockerfile 中替换
yum baseurl为 mirrors.aliyun.com/centos-vault 与 mirrors.nju.edu.cn/mlnx-ofed,避免 InfiniBand 驱动下载超时。 - 作业调度集成:Slurm 22.05+ 支持 --container 参数,需提前在 slurm.conf 配置
ContainerType=job_container_docker,并在节点安装 nvidia-container-toolkit 与 enroot,实现无 root 容器启动。
答案
-
镜像构建
- 基础镜像:采用 nvidia/cuda:12.2.0-devel-ubi8 作为 build 阶段,安装与宿主机相同版本 MLNX_OFED_LINUX-23.10-1.1.9.0-rhel8.6;编译 OpenMPI 4.1.6 时配置
--with-verbs --with-ucx --with-pmix=internal。 - 运行时镜像:使用 nvidia/cuda:12.2.0-runtime-ubi8,通过
yum install -y mlnx-ofed-basic-user-only-rpms安装用户态 RPM,确保 libmlx5.so.1 与宿主机驱动版本一致;用ldconfig -p | grep mlx5验证。 - 非 root 用户:创建 uid=1001 的 mpiuser,在镜像内执行
usermod -aG rdma mpiuser,避免运行时出现 “Operation not permitted”。
- 基础镜像:采用 nvidia/cuda:12.2.0-devel-ubi8 作为 build 阶段,安装与宿主机相同版本 MLNX_OFED_LINUX-23.10-1.1.9.0-rhel8.6;编译 OpenMPI 4.1.6 时配置
-
容器启动参数
docker run --rm \ --device /dev/infiniband/uverbs0 \ --device /dev/infiniband/rdma_cm \ --ipc=host --pid=host \ --cap-add=IPC_LOCK --cap-add=SYS_RESOURCE \ --ulimit memlock=-1:-1 \ --mount type=bind,source=/dev/hugepages,target=/dev/hugepages \ --network=host \ -u 1001:1001 \ my-registry.cn-hangzhou.cr.aliyuncs.com/hpc/mpi-openmpi:4.1.6-ib \ mpirun -np 2 --map-by ppr:1:node --bind-to none --mca btl_openib_warn_default_gid_prefix 0 --mca pml ucx --mca osc ucx /opt/hpc/benchmarks/imb/src/IMB-MPI1 PingPong关键点:
- --network=host 避免 Docker bridge 带来 2-3 µs 额外延迟;
- --mca pml ucx 强制使用 UCX 框架,自动选择 RC 传输,带宽可打满 100 Gbps。
-
多机调度
- 在 Slurm 环境,提交脚本内使用
srun --mpi=pmix --container-image=docker://my-registry.cn-hangzhou.cr.aliyuncs.com/hpc/mpi-openmpi:4.1.6-ib --container-name=mpijob mpirun /opt/hpc/benchmarks/imb/src/IMB-MPI1 Allreduce,Slurm 自动把 RDMA 设备映射到容器。 - 若中心未启用 enroot,可改用 pyxis 插件:
srun --mpi=pmix --container-image=... --container-mounts=/dev/infiniband:/dev/infiniband,实现非 root 容器。
- 在 Slurm 环境,提交脚本内使用
-
故障排查 checklist
- ibv_devinfo 在容器内能列出 mlx5_0 port 1 state ACTIVE;
- ib_write_bw 容器↔宿主机可跑满带宽,若出现 “cq creation failed”,检查 /sys/module/mlx5_core/parameters/probe_vf 是否为 0;
- 若出现 “UCX ERROR ibv_reg_mr failed: Cannot allocate memory”,确认
--ulimit memlock=-1已加,且宿主机 /etc/security/limits.conf 中 * soft memlock unlimited 已配置。
拓展思考
- RoCE v2 场景:国内部分 AI 集群采用 RoCE v2 替代 InfiniBand,此时需在容器内额外配置 --cap-add=NET_ADMIN 以支持 ECN 与 PFC 调优,并通过 tc qdisc 设置 prio 与流量类别。
- GPU Direct RDMA:在 NVIDIA A100 + NVSwitch 环境,容器需同时挂载 nvidia.com/gpu=all 与 InfiniBand 设备,并在 MPI 启动参数追加
--mca btl_smcuda_use_cuda_ipc 1 --mca pml_ucx_devices mlx5_0:1,实现 GPU 内存零拷贝跨节点传输,带宽可提升 15-20%。 - 安全加固:国内等保 3 级要求容器内禁止加载内核模块,可在 Dockerfile 中
rm -f /usr/sbin/modprobe,并通过 seccomp 白名单屏蔽 mount、umount、ptrace 系统调用,降低攻击面。