构建 OpenMPI Docker 镜像并运行 HPL 基准测试

解读

国内互联网、金融、政企云原生面试中,“能跑 HPL 的 OpenMPI 容器” 是高频动手题,用来验证候选人对多进程并行、CPU 绑核、RDMA 网络、镜像体积、CI/CD 集成的综合掌控。
面试官通常现场给出三台虚拟机(x86_64、CentOS 7.9、Docker 24.0),要求 30 min 内交付:

  1. 一个**≤200 MB** 的生产级镜像;
  2. 一条命令即可在3 节点、每节点 8 vCPU 环境跑出 ≥85 % 的 Linpack 效率;
  3. 容器内非 root 运行,SSH 免密由宿主机统一分发;
  4. 提供docker-compose.yml 一键复现,方便后续 GitLab CI nightly 回归。
    任何“镜像 1 GB+”“跑完效率 30 %”“用 root 启动 mpirun”都会直接挂掉。

知识点

  1. 多阶段构建:用 --from=builder 把编译依赖与运行依赖彻底分离,最终镜像只保留 OpenMPI runtime、HPL 二进制与 libgfortran
  2. CPU 拓扑感知:通过 --cpus 8 --cpuset-cpus 4-11mpirun --map-by slot:PE=1 --bind-to core 实现绑核,避免容器内只看到 1 vCPU 的尴尬。
  3. 高速网络透传:宿主机加载 mlx5_ib 时,容器需 --device /dev/infiniband --cap-add IPC_LOCK --ulimit memlock=-1,并在镜像里安装 libmlx5-1、rdma-core,否则 MPI 会退化到 TCP,效率腰斩。
  4. 非 root SSH:镜像内创建 mpiuser(1001:1001),宿主机统一注入 authorized_keysmpirun--mca plm_rsh_args "-p 2222" 避开容器 22 端口冲突。
  5. 镜像体积压缩:选用 ubuntu:22.04 基础,apt-get 后清理 /var/cache/apt,再用 docker build --squashdocker-slim 把最终镜像压到 180 MB
  6. CI/CD 友好:把 RUN apt-get … 换成国内清华源,.dockerignore 排除 .git、*.log,并在 GitLab CI 里做 docker buildx --cache-to type=local 加速。

答案

  1. 目录结构
hpl-mpi/
├── Dockerfile
├── docker-compose.yml
├── entrypoint.sh
├── hpl-2.3.conf  # 预调最优 block size
└── ssh/
    └── authorized_keys
  1. Dockerfile(国内源 + 多阶段)
# 阶段 1:builder
FROM ubuntu:22.04 AS builder
RUN sed -i 's|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list && \
    apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
    build-essential gfortran openmpi-bin libopenmpi-dev wget && \
    rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN wget -q https://www.netlib.org/benchmark/hpl/hpl-2.3.tar.gz && \
    tar xf hpl-2.3.tar.gz && cd hpl-2.3 && \
    ./configure --prefix=/opt/hpl ARCH=Linux_MPI && \
    make -j$(nproc) && make install

# 阶段 2:runtime
FROM ubuntu:22.04
RUN sed -i 's|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list && \
    apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
    openmpi-bin libopenmpi40 libgfortran5 rdma-core libmlx5-1 && \
    apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY --from=builder /opt/hpl /opt/hpl
COPY entrypoint.sh /entrypoint.sh
RUN useradd -m -u 1001 mpiuser && chmod +x /entrypoint.sh
USER mpiuser
ENV PATH=/opt/hpl/bin:$PATH
ENTRYPOINT ["/entrypoint.sh"]
  1. entrypoint.sh
#!/bin/bash
set -e
# 若宿主机传入 SSH_KEY,写入 authorized_keys
if [[ -n "$SSH_KEY" ]]; then
  mkdir -p ~/.ssh
  echo "$SSH_KEY" >> ~/.ssh/authorized_keys
  chmod 600 ~/.ssh/authorized_keys
fi
exec "$@"
  1. docker-compose.yml(三节点)
version: "3.9"
services:
  mpi-node:
    image: registry.cn-hangzhou.aliyuncs.com/yourname/hpl-mpi:2.3
    build: .
    user: "1001:1001"
    cap_add:
      - IPC_LOCK
    devices:
      - /dev/infiniband:/dev/infiniband
    ulimits:
      memlock: -1
    environment:
      - SSH_KEY=${SSH_KEY}
      - OMPI_MCA_btl=^openib
      - OMPI_MCA_pml=ucx
    networks:
      mpi-net:
        ipv4_address: 172.30.0.2
    command: ["sleep","infinity"]
networks:
  mpi-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.0.0/24
  1. 构建与运行
# 一次性构建
docker buildx build -t registry.cn-hangzhou.aliyuncs.com/yourname/hpl-mpi:2.3 --squash --push .

# 三节点启动
docker-compose up -d --scale mpi-node=3

# 生成主机列表
docker exec -it hpl-mpi-mpi-node-1 bash -c \
  "mpirun --host 172.30.0.2,172.30.0.3,172.30.0.4 -np 24 --map-by slot:PE=1 --bind-to core \
   xhpl"
  1. 结果验证
    运行结束出现
T/V                N    NB     P     Q               Time                 Gflops
--------------------------------------------------------------------------------
WR11C2R4       30000   256     3     8             123.45              2.345e+02

效率 ≥85 % 即达标;镜像体积 docker images 显示 183 MB

拓展思考

  1. ARM 与 x86 混合集群:国内信创场景常见鲲鹏 920 + Intel 8280 混部,需在 Dockerfile 里用 ARG TARGETARCH 区分,OpenMPI 需加 --enable-heterogeneous,并在 docker buildx 做多架构 manifest。
  2. RoCE v2 替代 IB:若只有以太网,可把基础镜像换成 nvidia/cuda:12.2.0-base-ubuntu22.04,用 UCX + RoCE 模式,同时把 btl_tcp_if_include 指向宿主机 eth1,避免跨 NUMA 拥塞。
  3. 安全加固:把 entrypoint.shSSH_KEY 改为从 HashiCorp Vault 拉取,镜像内删除 ssh-keygen,并用 docker-secretHPL.dat 敏感 block size 参数加密,满足金融等保 2.0 要求。
  4. Kubernetes 化:将上述 compose 改写成 MPIJob(Kube-batch 或 Volcano),通过 kubectl create -f mpijob.yaml 拉起 64 节点、2048 核,HPL 效率仍保持 ≥90 %,同时用 Prometheus + Grafana 监控容器内 hwloc 绑核热力图,方便后续调度器调优。