Sarus Suite:基于Podman的HPC容器化解决方案架构与实践
2026/6/24 5:07:17 网站建设 项目流程

1. 从HPC的“孤岛”到云原生的“桥梁”:为什么我们需要Sarus Suite?

在传统的高性能计算领域,我们常常面临一个尴尬的局面:一边是追求极致性能、稳定和可控的物理机或专用集群,另一边是灵活、敏捷、易于分发的容器化应用生态。长久以来,HPC环境就像一个坚固的“孤岛”,它依赖MPI、OpenMP、PGAS等并行编程模型,对网络、存储、调度器有着苛刻的要求。而Docker引领的容器化浪潮,虽然席卷了互联网和云计算,但在HPC的门口却屡屡碰壁。Docker daemon的守护进程模型、对root权限的依赖、与Slurm/PBS等调度器的集成复杂度,都让HPC系统管理员望而却步。这种割裂导致科学计算应用的开发、测试和部署流程异常繁琐,可重复性和可移植性大打折扣。

Sarus Suite的出现,正是为了在这道鸿沟上架起一座桥梁。它不是一个全新的容器运行时,而是一个基于Podman构建的、专门为HPC环境量身定制的容器系统架构。Podman作为Docker的替代品,其无守护进程、rootless运行、兼容Docker CLI的特性,为HPC集成提供了绝佳的基础。但仅有Podman还不够,HPC环境还需要容器能无缝地、高性能地使用InfiniBand/RoCE高速网络、GPU、并行文件系统,并且能被Slurm等作业调度器直接管理。Sarus Suite就是这套完整解决方案的集大成者。

简单来说,如果你在HPC集群上遇到过以下问题,那么Sarus Suite就是你该仔细研究的工具:

  • 想在集群上运行一个打包了复杂依赖(特定版本的CUDA、科学库)的容器化应用,但发现Docker因为权限问题根本装不上或用不了。
  • 容器内的进程无法直接使用集群的InfiniBand网络进行MPI通信,性能损失巨大。
  • 不知道如何让Slurm作业脚本直接启动和管理容器任务。
  • 需要一种安全、可审计、多租户的容器运行方式。

Sarus Suite通过一系列精巧的架构设计,让容器在HPC环境中变得“原生”。它让研究人员和工程师能够像在云平台上一样,使用容器来封装和分发他们的计算工作流,同时又能完全榨取底层HPC硬件的性能潜力。接下来,我们将深入拆解这套架构的核心设计思想与关键实践。

2. 核心架构解析:Sarus Suite如何重新定义HPC容器运行时

Sarus Suite的架构可以看作是对标准OCI容器运行时栈的“HPC化”增强。它并非推翻重来,而是在关键路径上插入了一系列钩子和封装器,以确保容器进程能够融入HPC环境。其核心架构主要包含以下几个层次:

2.1 基于Podman的无守护进程基础

Sarus选择Podman作为底层容器引擎,是其最根本也最明智的设计决策。与Docker的C/S架构不同,Podman采用fork-exec模型直接调用runc来创建容器。这意味着:

  • 无需守护进程:没有常驻的dockerd,消除了单点故障和安全风险,也简化了在共享HPC系统上的安装和权限管理。
  • 完美的Rootless容器:用户可以直接以自己的非特权身份创建和运行容器,这对于多租户的HPC中心至关重要。系统管理员无需担心用户通过容器获取主机root权限。
  • CLI兼容性sarus命令的设计很大程度上兼容docker命令,用户学习成本极低。例如,sarus pull,sarus run等命令对于熟悉Docker的用户来说非常直观。

然而,原生的Podman仍然只是一个通用的容器工具。Sarus在Podman之上构建了一个抽象层,这个层负责解释用户命令,并生成适合HPC环境的、最终的podman run命令。

2.2 OCI Hook机制:容器生命周期的精准干预

这是Sarus实现HPC集成的技术基石。OCI运行时规范定义了“hooks”,允许在容器生命周期的特定时刻(如prestart,poststart,poststop)执行自定义脚本。Sarus大量使用了prestarthook。

当用户执行sarus run时,大致流程如下:

  1. Sarus CLI解析命令和参数。
  2. 根据配置和参数,动态生成一个或多个OCI Hook的配置文件。
  3. 调用podman run,并通过--annotation等方式将Hook配置信息传递给底层的runc
  4. runc在启动容器进程前,执行prestarthook。这些hook是Sarus魔法的核心:
    • SSH Hook:在容器内启动一个SSH守护进程,并配置免密登录。这是为了让宿主机上的MPI启动器(如mpirun)能够通过SSH进入容器内部启动MPI进程。
    • MPI Hook:挂载宿主机上的MPI库(如OpenMPI, Intel MPI)到容器内,并调整容器内的LD_LIBRARY_PATH等环境变量。这确保了容器内应用使用的是与宿主机兼容的高性能MPI实现,从而支持高速网络。
    • GPU Hook:将宿主机的GPU设备文件(如/dev/nvidia*)和相关的驱动库挂载到容器中,使容器内应用可以直接使用GPU。
    • Globally-accessible filesystems Hook:将集群的并行文件系统(如Lustre, GPFS)挂载点以相同路径绑定挂载到容器内,保证容器内外访问存储的路径一致性。

通过这套Hook机制,Sarus实现了“开箱即用”的HPC能力注入。用户无需手动在容器镜像中配置复杂的SSH、MPI或存储,Sarus在运行时自动完成。

2.3 与作业调度器的深度集成:以Slurm为例

在HPC中,一切计算资源都由调度器管理。Sarus必须能与Slurm、PBS等调度器协同工作。集成方式通常有两种:

  1. 在Slurm作业脚本中直接调用sarus:这是最常见的方式。用户在一个Slurm提交脚本中,使用srunmpirun来启动任务,而命令的核心是sarus run

    #!/bin/bash #SBATCH --job-name=my-sarus-job #SBATCH --nodes=2 #SBATCH --ntasks-per-node=4 #SBATCH --gres=gpu:1 # 使用 srun 启动,srun 会在每个计算节点上执行后面的命令 srun sarus run \ --mpi \ myregistry.com/hpc-app:latest \ ./my_mpi_application

    srun在多个节点上执行该命令时,每个节点上的Sarus都会独立启动容器,并通过预先配置的SSH实现跨节点的MPI进程间通信。

  2. 使用spank_sarusSlurm插件:这是更优雅、更集成的方案。SPANK是Slurm的插件接口。spank_sarus插件会在Slurm任务启动的早期被调用,自动为任务注入必要的环境变量和挂载信息,甚至可以自动拉取镜像。对用户来说,他们几乎感觉不到容器的存在,就像在运行一个原生二进制文件一样。

    #SBATCH ... # 同上 # 无需在命令中显式写出 sarus,插件会处理 srun ./my_mpi_application

    这种方式对用户最友好,但需要系统管理员在集群层面进行安装和配置。

2.4 镜像仓库与安全考量

Sarus支持标准的OCI镜像仓库(如Docker Hub, Quay.io, 或私有的Harbor)。对于HPC中心,通常会搭建一个本地镜像仓库,一方面加速镜像拉取,另一方面也便于进行安全扫描和审计。

安全是HPC的重中之重。Sarus的rootless模式奠定了安全基础。此外,管理员可以通过Sarus的配置文件严格限制用户行为,例如:

  • 限制可拉取的镜像仓库白名单。
  • 禁用容器的--privileged模式。
  • 控制哪些宿主机目录可以绑定挂载到容器内。
  • 配合cgroups限制容器对CPU、内存等资源的使用,确保符合作业调度器的分配。

3. 关键组件与工作流程深度拆解

理解了宏观架构,我们再深入到几个关键组件的工作细节,这能帮助我们在遇到问题时进行排查。

3.1sarusCLI:用户接口与命令转换器

sarus命令行工具是用户的主要交互界面。它做的事情远比看上去多。当你键入sarus run --mpi -v /data:/data nvidia/cuda:11.8-runtime ./app时:

  1. 参数解析与验证:CLI首先解析所有参数。它会检查--mpi标志,准备触发MPI hook;检查-v绑定挂载,确保路径在允许列表内(根据/etc/sarus.json配置)。
  2. 镜像处理:如果镜像在本地不存在,它会调用podman pull(或skopeo)从配置的仓库拉取。Sarus支持缓存镜像层以提升效率。
  3. 生成OCI Bundle:Sarus会在一个临时目录(如/var/sarus/...)为这个容器运行实例准备一个OCI Bundle。这包括:
    • config.json: 容器的运行时配置。Sarus会在这里插入它生成的hook配置
    • 容器的rootfs:通常通过overlayfs联合挂载实现。
  4. 构造最终的podman run命令:这是核心步骤。Sarus不会直接创建容器,而是生成一个长长的、包含所有必要参数的podman run命令。例如,它会添加:
    • --annotation: 传递hook配置。
    • --security-opt label=disable: 在SELinux环境下可能需要。
    • --device: 用于GPU设备。
    • --volume: 用于绑定挂载存储和MPI库。
    • --env: 设置特定的环境变量,如OMPI_MCA_btl_openib_allow_ib=1以启用InfiniBand。
  5. 执行与代理:最后,Sarus fork/exec执行这个构造好的podman run命令,并可能代理容器的标准输入/输出。

注意:一个常见的困惑点是,用户以为sarus是一个独立的运行时。实际上,它是一个智能的“翻译官”和“组装工”,将用户友好的sarus命令翻译成复杂的、HPC友好的podman run命令。理解这一点对调试至关重要——当你遇到容器启动失败时,可以尝试让Sarus输出它生成的最终命令(有些版本支持--debug参数),然后手动用podman run执行该命令,往往能更快定位问题。

3.2 Hook的执行环境与依赖隔离

Hook脚本本身在宿主机环境下执行,但拥有容器的命名空间视图。这意味着:

  • MPI Hook:它需要知道宿主机上MPI库的安装路径。这个路径通常在Sarus的全局配置文件/etc/sarus.json中定义。Hook的工作就是把/usr/mpi(例如)挂载到容器内的相同路径,并确保容器内的LD_LIBRARY_PATH包含该路径。这样,容器内的MPI程序在运行时,动态链接到的是宿主机的高性能MPI库,而非容器内可能存在的(或不存在的)版本。
  • 依赖冲突风险:这里存在一个潜在问题。如果容器镜像内已经自带了MPI库(比如一个基于Ubuntu并安装了mpich的镜像),而宿主机使用的是OpenMPI。Hook挂载宿主机库后,可能会因为库版本或ABI不兼容导致程序崩溃。最佳实践是:构建HPC容器镜像时,通常不安装MPI库,或者仅安装最小化的运行时依赖,将MPI的实现完全交给宿主机环境。镜像只包含应用代码和其非MPI的第三方库依赖。

3.3 跨节点通信:SSH + MPI的协同

这是Sarus实现分布式内存并行计算的关键。假设你在2个节点上各运行4个MPI进程:

  1. 容器启动:在每个计算节点上,Slurm的srun启动了一个sarus run命令,进而启动了一个容器。每个容器内部,SSH hook都启动了一个sshd
  2. MPI启动:用户命令中可能直接是MPI程序,或者由srun启动mpirun。以OpenMPI为例,mpirun会读取Slurm提供的机器文件(hostfile),知道任务分布在哪些节点上。
  3. 进程启动mpirun通过SSH连接到其他节点。由于容器内的sshd配置了与宿主机共享的密钥,mpirun可以无缝登录到其他节点上的容器内部
  4. 启动远程进程:登录后,mpirun在远程容器内执行命令,启动MPI进程。因为所有容器内通过Hook挂载的MPI库路径是一致的,所以远程进程能正确链接。
  5. 高速网络通信:启动后的MPI进程,通过MPI库调用底层通信API(如OpenFabrics Interfaces, OFI)。由于容器进程使用了宿主机的MPI库,而宿主机MPI库在编译时已经支持了InfiniBand驱动,因此进程间的通信可以直接绕过TCP/IP,通过InfiniBand Verbs API进行,实现接近裸机的网络性能。

实操心得:跨节点SSH配置是故障高发区。务必确保Sarus配置的SSH密钥对在集群计算节点之间是互通的,且sshd在容器内的启动参数正确。一个调试技巧是,先不用MPI,尝试用sarus run在两个节点上分别启动容器,然后在一个容器内手动SSH到另一个容器的IP,测试连通性。排除了SSH问题,MPI的问题就解决了一大半。

4. 实战部署与配置指南

理论说得再多,不如动手配置一遍。下面以一个基于Slurm的集群为例,概述系统管理员部署Sarus Suite的关键步骤。

4.1 前提条件与安装

  1. 集群环境:一个正在运行的Slurm集群,计算节点间SSH免密互通。节点上已安装高性能MPI库(如OpenMPI)和驱动(如OFED for InfiniBand)。
  2. 安装Podman:在所有计算节点和登录节点上安装Podman。确保版本兼容性。需要配置rootless模式,通常需要调整/etc/subuid/etc/subgid文件,让普通HPC用户拥有映射到足够数量子UID/GID的能力。
    # 例如,在RHEL/CentOS系列上 sudo yum install -y podman # 配置用户命名空间映射 echo "$USER:100000:65536" | sudo tee -a /etc/subuid echo "$USER:100000:65536" | sudo tee -a /etc/subgid
  3. 安装Sarus:从GitHub Release页面下载最新版本的Sarus二进制包或使用RPM/DEB包安装。需要安装在所有节点上。
    # 示例:解压并安装到 /opt/sarus tar -xzf sarus-<version>.tar.gz -C /opt ln -s /opt/sarus-<version> /opt/sarus
  4. 配置Sarus:核心配置文件是/etc/sarus.json。需要配置的关键部分包括:
    • OCIBundleDir: 容器Bundle的生成目录,需要一个大容量的临时文件系统(如/tmp或专用的/scratch)。
    • rootfsDirectory: 镜像解压层的目录。
    • mountedFiles: 定义要挂载到所有容器中的文件,如/etc/hosts,/etc/passwd(只读)以保持用户信息。
    • securityChecks: 启用或禁用安全特性。
    • ssh: SSH Hook的配置,指定密钥路径、容器内sshd的路径等。
    • mpi: MPI Hook的配置,指定宿主机MPI库的安装路径。
    • registries: 允许拉取镜像的仓库列表,可以配置认证信息和TLS验证。

4.2 集成Slurm(使用SPANK插件)

  1. 编译spank_sarus插件:Sarus源码中提供了插件。进入sarus_source/spank目录,根据Slurm版本进行编译。
    ./configure --prefix=/usr/local SLURM_VERSION=21.08.2 # 根据实际Slurm版本修改 make sudo make install
    这会将spank_sarus.so安装到Slurm的插件目录。
  2. 配置Slurm:编辑Slurm的配置文件(通常是/etc/slurm/slurm.conf/etc/slurm/plugstack.conf),启用该插件。
    # 在 plugstack.conf 中添加 required /usr/local/lib/slurm/spank_sarus.so
  3. 配置插件:创建/etc/sarus/spank.json,定义插件行为,例如默认镜像、是否自动拉取等。

4.3 用户端体验与示例

配置完成后,用户的使用体验可以非常流畅。

示例1:运行一个简单的GPU加速容器

# 交互式作业 salloc -N 1 -G 1 --gres=gpu:1 sarus run --tty --gpu nvcr.io/nvidia/pytorch:23.10-py3 python -c "import torch; print(torch.cuda.is_available())" # 输出应为:True

示例2:提交一个多节点MPI作业脚本

#!/bin/bash #SBATCH --job-name=sarus-mpi-test #SBATCH --nodes=2 #SBATCH --ntasks-per-node=4 #SBATCH --partition=compute # 使用 spank_sarus 插件时,甚至可以不显式调用 sarus # 但这里展示显式调用 srun sarus run \ --mpi \ myharbor.example.com/hpc/mpi-benchmark:latest \ /opt/mpi-benchmarks/src/IMB-MPI1 PingPong

用户只需要关心自己的应用和镜像,无需处理复杂的MPI库安装、网络配置和跨节点启动问题。

5. 性能调优、故障排查与最佳实践

将容器用于生产级HPC,性能和稳定性是生命线。以下是一些关键的经验和技巧。

5.1 性能调优要点

  1. 镜像构建优化

    • 使用多阶段构建:最终镜像只包含运行时必要的文件,减少镜像层数和体积,加速拉取和启动。
    • 选择合适的基础镜像:推荐使用ubi-microdebian:stable-slim等极小化镜像。避免使用ubuntu:latest这类包含大量非必要软件的大镜像。
    • 层缓存策略:将不经常变化的依赖安装(如系统包更新、基础库)放在Dockerfile的前面,将经常变化的代码复制放在后面。
  2. 存储I/O优化

    • 绑定挂载并行文件系统:务必使用-v将集群的并行文件系统(如/lustre)挂载到容器内相同路径。避免在容器内进行大量数据读写,应直接读写绑定挂载的路径。
    • 注意OverlayFS开销:容器的可写层(upperdir)使用OverlayFS。如果应用会产生大量小文件或频繁写入,这可能会成为瓶颈。考虑将临时目录或输出目录挂载到内存文件系统(tmpfs)或高性能本地SSD上。
      sarus run --mount=type=tmpfs,destination=/tmp ...
  3. 网络与MPI优化

    • 确保InfiniBand支持:确认宿主机MPI库已启用InfiniBand支持,并且容器内进程通过Hook正确链接到了该库。可以通过在容器内运行ompi_info | grep btl来检查OpenMPI的传输层是否包含openib
    • 进程绑定:像原生作业一样,使用--cpu-bind--mem-bind等Slurm参数或MPI环境变量进行进程与CPU/内存的绑定,减少NUMA效应的影响。

5.2 常见故障排查

  1. 容器启动失败:permission denied

    • 检查rootless配置:确认用户已正确配置/etc/subuid/etc/subgid。使用podman unshare cat /proc/self/uid_map检查映射是否生效。
    • 检查临时目录权限:Sarus的OCIBundleDirrootfsDirectory对应的目录,必须对运行用户可写。
  2. MPI作业卡住或失败

    • SSH连接问题:这是首要怀疑对象。在作业脚本开头加入export SARUS_SSH_LOG_LEVEL=DEBUG来获取详细的SSH日志。检查计算节点间的SSH免密登录是否正常,以及容器内的sshd是否成功启动(查看/var/log/sarus/ssh*.log)。
    • MPI库不兼容:在容器内运行ldd /path/to/your/mpi/app,查看链接的MPI库是否来自宿主机挂载的路径。对比宿主机和容器内mpirun --version的输出。
    • 网络设备未找到:如果MPI报错找不到InfiniBand设备,检查Hook是否成功挂载了/dev/infiniband目录(如果MPI库需要)。可能需要额外配置Sarus的devices列表。
  3. GPU不可用

    • 检查设备挂载:使用sarus run --tty --gpu nvidia/cuda:11.8-runtime nvidia-smi测试。如果失败,检查Sarus配置中device部分是否包含了NVIDIA设备文件。
    • 驱动兼容性:确保宿主机NVIDIA驱动版本与容器内CUDA Toolkit版本兼容。

5.3 安全与多租户最佳实践

  1. 严格的镜像仓库策略:只允许从受信任的内部仓库拉取镜像。对所有入库镜像进行漏洞扫描。
  2. 资源限制:虽然Slurm控制了作业层面的资源,但仍建议在Sarus或Podman层面使用cgroups对单个容器的资源使用(如内存、PIDs数量)设置上限,防止单个容器耗尽节点资源。
  3. 审计日志:启用Sarus和Podman的详细日志,记录所有镜像拉取和容器运行事件,便于事后审计和故障追溯。
  4. 用户教育:培训用户构建安全、高效的HPC容器镜像,避免在镜像中放入敏感信息,鼓励使用多阶段构建。

从我个人的部署和使用经验来看,Sarus Suite的成功应用,30%在于软件本身的正确安装,70%在于对HPC环境和容器技术交织点的深刻理解与细心配置。它不是一个“一键部署”的魔法黑盒,而是一个强大的工具,当你清晰地知道它在每个环节做了什么,你就能驾驭它,让容器化真正为HPC科研与工程赋能。最初的调试阶段可能会遇到各种网络、权限、依赖问题,但一旦打通,它为团队带来的开发效率提升和应用部署的标准化收益将是巨大的。对于正在寻求现代化其HPC软件交付流程的团队来说,投入时间评估和部署Sarus Suite,是一项非常值得的投资。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询