在 InfiniBand 网络下如何容器化 MPI 程序

解读

国内金融、超算、AI 训练中心普遍采用 Mellanox InfiniBand 作为高性能计算网络,容器化 MPI 程序时必须解决 RDMA 设备直通、用户态驱动一致性、进程启动模型、作业调度集成 四大痛点。面试官希望听到“从镜像构建到作业提交”全链路落地经验,而非简单跑通 hello-world。

知识点

  1. InfiniBand 内核栈:mlx5_core、mlx5_ib、ib_core 模块版本需与宿主机一致,容器内禁止升级。
  2. 用户态库版本锁定:libmlx5、librdmacm、libibverbs 版本必须与 OFED 驱动版本 严格对应,否则出现 “cannot allocate PD” 类错误。
  3. RDMA 设备直通--device /dev/infiniband/uverbs0 --device /dev/infiniband/rdma_cm 同时挂载,缺一不可。
  4. IPC 与 PID namespace:MPI 需要共享内存,必须 --ipc=host --pid=host;若用 Slurm,则 srun 自带 --mpi=pmix 可自动注入。
  5. 特权与 Capabilities:国内超算中心出于安全审计,通常禁止 --privileged,需显式 --cap-add=IPC_LOCK --cap-add=SYS_RESOURCE
  6. HugePage 预留:HPC 作业调度系统(如 Slurm、PBS Pro)已预分配 HugePage,容器需挂载 /dev/hugepages 并设置 --ulimit memlock=-1
  7. 进程管理模型:OpenMPI 4.x 默认采用 PMIx + prrte,容器镜像需内置 prrte 守护进程,并通过 --pid=host 保证宿主机与容器进程树一致。
  8. 镜像多阶段构建:第一阶段用 nvidia/cuda:12.2.0-devel-ubi8 安装 OFED、编译 MPI;第二阶段用 nvidia/cuda:12.2.0-runtime-ubi8 仅拷贝运行时库,镜像体积从 3.8 GB 压缩到 980 MB,符合国内私有仓库配额限制。
  9. 国内源加速:在 Dockerfile 中替换 yum baseurlmirrors.aliyun.com/centos-vaultmirrors.nju.edu.cn/mlnx-ofed,避免 InfiniBand 驱动下载超时。
  10. 作业调度集成:Slurm 22.05+ 支持 --container 参数,需提前在 slurm.conf 配置 ContainerType=job_container_docker,并在节点安装 nvidia-container-toolkitenroot,实现无 root 容器启动。

答案

  1. 镜像构建

    • 基础镜像:采用 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”
  2. 容器启动参数

    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。
  3. 多机调度

    • 在 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 容器。
  4. 故障排查 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 已配置。

拓展思考

  1. RoCE v2 场景:国内部分 AI 集群采用 RoCE v2 替代 InfiniBand,此时需在容器内额外配置 --cap-add=NET_ADMIN 以支持 ECNPFC 调优,并通过 tc qdisc 设置 prio 与流量类别
  2. GPU Direct RDMA:在 NVIDIA A100 + NVSwitch 环境,容器需同时挂载 nvidia.com/gpu=allInfiniBand 设备,并在 MPI 启动参数追加 --mca btl_smcuda_use_cuda_ipc 1 --mca pml_ucx_devices mlx5_0:1,实现 GPU 内存零拷贝跨节点传输,带宽可提升 15-20%。
  3. 安全加固:国内等保 3 级要求容器内禁止加载内核模块,可在 Dockerfile 中 rm -f /usr/sbin/modprobe,并通过 seccomp 白名单屏蔽 mount、umount、ptrace 系统调用,降低攻击面。