快速提交MPI任务
在大规模分布式训练场景中,MPI(Message Passing Interface) 是一种成熟、稳定的进程通信模型,广泛应用于高性能计算(HPC)与深度学习分布式训练。
百舸平台 提供的 MPI 类型的工作负载,使得用户可以在 Kubernetes 环境中以原生方式运行 MPI 训练任务,适用于:
- 多节点、多 GPU 训练
- 需要精细控制进程拓扑与通信方式的任务
- 基于 NCCL // RDMA 的高性能通信场景
- 框架层(PyTorch / Horovod / Megatron / DeepSpeed 等)对 MPI 兼容良好的训练任务
MPI 训练基本原理
MPI 进程模型
MPI 采用 多进程(Multi-Process) 模型:
- 每个训练进程拥有独立的进程空间
- 进程之间通过 MPI 通信库进行点对点或集合通信
- 每个进程有唯一的
RANK - 所有进程共享
WORLD_SIZE
常见逻辑关系如下:
| 概念 | 含义 |
|---|---|
| WORLD_SIZE | 全局进程总数 |
| RANK | 当前进程在全局中的编号 |
| LOCAL_RANK | 当前节点内的进程编号 |
| NODE_RANK | 节点编号 |
在 GPU 训练中,通常 1 个 MPI 进程绑定 1 张 GPU。
工作机制
MPI Operator 主要由以下角色组成:
-
MPI Launcher
- 负责执行
mpirun - 生成 hostfile
- 拉起 Worker Pod 中的 MPI 进程
- 负责执行
-
MPI Worker
- 实际运行训练进程
- 提供计算资源(CPU / GPU / RDMA)
整体流程如下:
- MPIJob 提交:用户通过百舸平台提交 MPIJob 自定义资源,配置任务命令、Worker 数量、资源规格及镜像信息,触发任务调度流程。
- Launcher Pod 启动:集群优先调度 Launcher Pod,作为 MPI 任务的主控入口,其成功启动是后续 Worker 调度的前提。
- hostfile 自动注入:MPI Operator 在检测到 Launcher 与 Worker Pod 就绪后,自动收集 Worker 节点信息并生成标准
hostfile,注入至 Launcher 容器。 - mpirun 启动 Worker 进程:Launcher Pod 内执行
mpirun,基于hostfile通过 SSH 或 PMI 协议在各 Worker Pod 中拉起 MPI 进程。 - MPI / NCCL 通信执行:所有 Worker 进程启动完成后,进入业务执行阶段,通过 MPI 或 NCCL 完成参数同步与计算协同,直至任务结束。
镜像依赖与环境准备
| 项目 | 要求 |
|---|---|
| 运行用户 | root |
| MPI | 镜像中必须包含 mpirun |
| SSH | 支持 root 用户 SSH 免密登录 |
| sshd | Worker 容器中必须可启动 sshd |
| 配置文件 | /etc/ssh/sshd_config 中关闭 StrictModes |
本文测试镜像:
1registry.baidubce.com/cce-plugin-dev/deepspeed-training:23.08-gpu-py310-cu122-ubuntu22.04
MPI 启动方式与命令结构
基本 mpirun 结构
1mpirun \
2 --hostfile /etc/mpi/hostfile \ # MPI Operator 自动生成的 Worker 节点列表,默认通常无需配置
3 -np 4 \ # (按实际调整,如 2 Worker × 2 进程/卡)
4 -bind-to none \ # 避免与 K8s GPU/CPU 调度冲突
5 -map-by slot \ # 均匀分配进程到 GPU 节点
6 -x NCCL_DEBUG=INFO \ # NCCL 调试(生产可改 WARN)
7 -x NCCL_IB_DISABLE=1 \ # 禁用无用的 InfiniBand
8 python /app/train.py # 替换为你的业务脚本
参数说明
OpenMPI 的 mpirun 参数繁多,以下按功能分类梳理核心参数:
1.进程管理类
| 参数 | 完整写法 | 作用 | 场景使用建议 |
|---|---|---|---|
-np |
--np <num> |
指定总 MPI 进程数 | 必配:值需匹配 Worker Pod 数 × 每个 Pod 进程数(如 2 Worker × 2 进程 = -np 4) |
-npernode |
--npernode <num> |
每个节点(Worker Pod)启动的进程数 | 推荐使用:显式控制每个 Worker Pod 的进程数(如 -npernode 2),避免进程分配不均 |
--hostfile |
--hostfile <path> |
指定节点列表文件 | 路径固定为 /etc/mpi/hostfile(MPI Operator 自动生成,包含所有 Worker Pod 的 IP / 端口) |
--host |
--host <host1:slot1,host2:slot2> |
手动指定节点(替代 hostfile) | 禁用:MPI Operator 已自动生成 hostfile,手动指定会冲突 |
-oversubscribe |
--oversubscribe |
允许进程数超过节点 slot 数 | 谨慎使用:仅当 K8s 资源充足时临时调试,生产环境禁用(易导致资源耗尽) |
2. 通信配置类
| 参数 | 完整写法 | 作用 | 场景使用建议 |
|---|---|---|---|
-mca pml <layer> |
--mca pml <layer> |
指定进程间通信层(PML) | -mca pml ob1(OpenMPI 4.x 稳定版,适配 K8s 网络);禁用 ucx(K8s 集群中易出网络问题) |
-mca btl <layers> |
--mca btl <layers> |
指定字节传输层(BTL) | -mca btl tcp,self(K8s 集群内通信基于 TCP,self 仅兜底);禁用 openib(无 InfiniBand 时会报错) |
-mca btl_tcp_if_exclude <iface> |
- | 排除指定网卡 | -mca btl_tcp_if_exclude lo,docker0(排除本地回环 / 容器网卡,强制使用集群通信网卡) |
-mca btl_tcp_if_include <iface> |
- | 仅使用指定网卡 | 若集群有专用通信网卡(如 eth0),可指定 -mca btl_tcp_if_include eth0 |
-mca oob_tcp_if_exclude <iface> |
- | 排除 OOB(带外通信)网卡 | 同 btl_tcp_if_exclude,推荐同步配置 |
3. 资源绑定类
| 参数 | 作用 | MPI Operator 场景使用建议 |
|---|---|---|
-bind-to <type> |
绑定进程到 CPU 核心 / NUMA 节点 / 无绑定 | -bind-to none(禁用绑定,交给 K8s 调度);禁用 core/socket(易导致资源冲突) |
-map-by <type> |
进程分配策略 | -map-by slot(按 slot 均匀分配进程,适配 K8s Pod 资源模型);禁用 node/core(分配不均) |
--report-bindings |
打印进程绑定信息 | 调试 / 验证时使用,确认进程未被错误绑定 |
4. 环境变量传递类
Launcher Pod 的环境变量不会自动同步到 Worker,需显式传递核心变量:
| 参数 | 作用 | 场景使用建议 |
|---|---|---|
-x <var> |
传递单个环境变量到所有 Worker | 至少传递 -x PATH(保证命令可执行)、-x LD_LIBRARY_PATH(保证依赖库找到);GPU 任务需加 -x NCCL_DEBUG=INFO(调试)、-x NCCL_SOCKET_IFNAME=eth0(指定 NCCL 通信网卡) |
-x <var>=<value> |
传递并覆盖环境变量值 | 推荐:如 -x NCCL_DEBUG=INFO、-x CUDA_VISIBLE_DEVICES=0 |
--env-file <file> |
从文件读取环境变量传递 | 环境变量多时使用,文件每行格式 VAR=VALUE |
5. 调试 / 日志类
| 参数 | 作用 | 场景使用建议 |
|---|---|---|
-v/--verbose |
打印详细启动日志 | 调试时使用,排查进程启动失败问题 |
--debug |
打印调试级日志 | 仅深度排查时使用(日志量大) |
-mca orte_base_help_aggregate 0 |
禁用日志聚合,每个进程单独输出 | 调试时使用,定位单个 Worker 日志问题 |
--display-map |
打印进程分配映射(哪个进程在哪个 Worker) | 验证进程分配是否符合预期 |
6. 容错 / 超时类
| 参数 | 作用 | 场景使用建议 |
|---|---|---|
-timeout <sec> |
任务超时时间(秒) | -timeout 3600(1 小时),防止任务卡死占用资源 |
-mca plm_rsh_no_tree_spawn 1 |
禁用树形启动,直接启动所有进程 | K8s 集群中稳定性更高 |
-mca orte_abort_on_non_zero_status 1 |
任意进程非 0 退出时,整个任务终止 | 生产环境保证任务原子性 |
--leave-sessions-attached |
进程退出后保留会话,方便排查 | 调试时使用,生产环境禁用 |
7. 其他实用类
| 参数 | 作用 | 场景使用建议 |
|---|---|---|
-quiet |
静默模式,仅打印错误日志 | 推荐:生产环境使用,减少日志量 |
--tag-output |
给每个进程的输出打标签(进程 ID) | 推荐:分布式任务日志排障,区分不同进程输出 |
-wdir <path> |
指定所有进程的工作目录 | 推荐:统一设置为业务代码目录(如 -wdir /app |
hostfile 说明
百舸平台会自动为MPI 任务注入 /etc/mpi/hostfile,示例如下:
1job-xxx-worker-0.job-xxx-worker.default.svc slots=8
2job-xxx-worker-1.job-xxx-worker.default.svc slots=8
用户无需手动创建或修改 hostfile。
MPI任务实践
本文档介绍在百舸平台中使用 DeepSpeed 进行分布式训练的最佳实践,我们以 2 个 worker 节点、每个节点配备 2个 GPU 的典型集群配置为例,展示如何正确配置和启动训练任务。本方案的 MPI 核心参数配置具有通用性,可适配各类MPI任务,根据参数和代码做适当调整即可。
示例镜像
镜像中包含CIFAR10数据集位于/root/code/training/data,训练代码位于/root/code/training/cifar10_deepspeed.py,参考https://github.com/deepspeedai/DeepSpeedExamples/blob/master/training/cifar/cifar10_deepspeed.py
1registry.baidubce.com/cce-plugin-dev/deepspeed-training:23.08-gpu-py310-cu122-ubuntu22.04
启动命令详解
1.启动命令
1mpirun -np 4 \
2 -bind-to none -map-by slot \
3 -mca pml ob1 -mca btl ^openib \
4 -x NCCL_DEBUG=INFO \
5 python /root/code/training/cifar10_deepspeed.py \
6 --deepspeed \
7 --epochs 128 \
8 --stage 2 \
9 --dtype fp16 \
10 --log-interval 100
2.基础MPI命令说明
1mpirun -np 4 \
2 --hostfile /etc/mpi/hostfile \
3 --allow-run-as-root \
4 -bind-to none -map-by slot \
5 -mca pml ob1 -mca btl ^openib \
6 python /root/code/training/cifar10_deepspeed.py
参数解析:
-np 4:启动4个进程,对应2个节点×2个GPU的总GPU数量--hostfile /etc/mpi/hostfile:指定集群节点配置--allow-run-as-root:在容器化环境中允许以root身份运行-bind-to none -map-by slot:将进程按slot映射到各个GPU-mca pml ob1 -mca btl ^openib:使用TCP通信而非InfiniBand,提高兼容性
3.DeepSpeed相关参数说明
1 --deepspeed \
2 --epochs 128 \
3 --stage 2 \
4 --dtype fp16 \
5 --log-interval 100 \
6 --micro-batch-size 2 \
7 --gradient-accumulation-steps 1
参数解析:
--deepspeed:启用DeepSpeed训练引擎--stage 2:使用ZeRO Stage 2优化,在保持训练速度的同时显著减少显存占用--dtype fp16:使用半精度浮点数训练,减少显存使用并加速计算--micro-batch-size:每个GPU上的批次大小--gradient-accumulation-steps:梯度累积步数,用于模拟更大批次训练
控制台配置
创建分布式训练任务,关键参数如下:
- 训练镜像:使用
registry.baidubce.com/cce-plugin-dev/deepspeed-training:23.08-gpu-py310-cu122-ubuntu22.04 - 执行命令粘贴上述的启动命令
- 训练框架选择 MPI
- 资源配置:这里一共是 4 张卡,选择配置 2 个节点,每个节点 2 张卡

训练启动运行:
常见问题(FAQ)
sshd 启动失败:Missing privilege separation directory: /run/sshd
原因:容器中 /run/sshd 不存在
解决方案:构建镜像时添加如下命令
1mkdir -p /run/sshd
2chmod 0755 /run/sshd
mpirun 无输出或任务挂起
常见原因:
- Worker Pod 中 sshd 未运行
- SSH 端口未监听
- SSH 认证失败
排查命令:
1ps aux | grep sshd
2ss -lntp | grep :22
SSH 认证失败:Permission denied (publickey)
建议配置:
- root 用户
/root/.ssh/id_rsa/root/.ssh/authorized_keyssshd_config中关闭StrictModes
禁止 root 运行
1mpirun has detected an attempt to run as root
解决方案:添加启动参数
1--allow-run-as-root
MPI环境中错误使用DeepSpeed启动
MPI已负责进程管理和rank分配,DeepSpeed再次启动会导致二次进程拉起和rank冲突
1# 正确做法
2mpirun -np 8 python train.py
3# 错误做法
4mpirun -np 8 deepspeed train.py
关键:MPI模式下,DeepSpeed只作为训练库使用,禁用其启动器功能。
mpirun直接执行shell脚本失败
mpirun不会自动解析脚本解释器,远程节点可能无法识别脚本格式。
需要显式指定bash解释器执行脚本。
1# 正确做法
2mpirun -np 8 bash run.sh
3# 错误做法
4mpirun -np 8 run.sh
建议:脚本首行添加#!/usr/bin/env bash,确保使用bash而非sh。
评价此篇文章
