一、Singularity 简介与发展历史
1.1 这玩意儿到底解决了什么问题?
聊容器技术,大家第一反应肯定是 Docker。没错,Docker 改变了运维和微服务的玩法。但如果你在超算中心、在 SLURM 集群上跑 MPI 并行任务,或者用着老旧的操作系统(比如 RHEL 6),你就知道 Docker 有多「水土不服」了。
为什么?因为 Docker 默认就有 daemon 进程,需要 root 权限,还跟系统的 cgroups 和 namespace 深度绑定。这在开发机上没问题,但在上百个节点同时部署的 HPC 环境里,你想想看——权限冲突、网络配置碎片化、安全问题层出不穷。我最初接手一个 MPI 项目时,就踩过这坑,最后被迫把所有依赖编译成静态二进制文件……那叫一个痛苦。
1.2 Singularity 的核心设计理念
Singularity 就是针对这些痛点诞生的。它的设计哲学很纯粹:以用户身份运行,不依赖特权 daemon,直接与宿主机的内核交互。
说白了,它把整个容器打包成一个单一的「SIF」镜像文件。你拿到这个 .sif 文件后,不需要解压、不需要启动守护进程,直接 singularity run 就能跑。而且它完全兼容 Docker 的镜像格式——这一点非常关键,意味着你可以从 Docker Hub 或已有 registry 中拉镜像,然后无缝衔接到 HPC 环境中。
1.3 发展历史与关键版本
我记得最早接触 Singularity 是在 2016 年,那时它还叫 Singularity 1.x,是由 Lawrence Berkeley 国家实验室开发的。当时功能非常简单,只支持简单的 sandbox 模式和 squashfs 打包。但方向非常明确:让科学家可以用容器复现实验环境。
随后版本迭代的速度很快。我整理一下关键节点:
| 版本 | 发布时间 | 关键变化 |
|---|---|---|
| 1.x | 2016 | 初始版本;sandbox 模式;基本 run/exec/shell 命令 |
| 2.x | 2017 | 引入 registry 支持;原生 GPU 支持;MPI 集成;.simg 镜像格式 |
| 3.x | 2018 | 完全重构;采用 SIF 格式;引入实例管理;OCI 兼容性改进 |
| 4.x | 2023 | 复数实例支持;增强的加密功能;CDC 和 HPC 生态深度整合 |
1.4 Docker vs Singularity:核心差异
其实很多刚接触的同学会问:「既然 Docker 也能跑,为什么还要用 Singularity?」
这个问题我回答过不下 50 次。我从几个最关键的维度做一个对比:
| 维度 | Docker | Singularity |
|---|---|---|
| 运行方式 | 需要 root 或加入 docker 组 | 以当前用户 UID/GID 运行,无需提权 |
| 守护进程 | 必须启动 dockerd daemon | 无守护进程,直接用 CLI 二进制文件操作 |
| 镜像格式 | 多层 tar + 元数据 | 单文件 SIF(SquashFS + JSON 描述) |
| 网络模型 | 独立网桥,自动管理网络 namespace | 与宿主机共享网络栈,默认不隔离 |
| GPU/MPI 支持 | 需要 nvidia-docker 等额外工具 | 原生支持 --nv 和 --mpi 参数 |
| 安全隔离 | 强 namespace 隔离,但逃逸后影响大 | 弱隔离但强信任:容器内用户 ID 与外部一致 |
singularity exec 替换 docker run,问题迎刃而解。所以如果你的环境是 HPC/ML 训练/科学计算,直接用 Singularity 可以少踩 80% 的坑。
1.5 Singularity 的适用场景
根据我实际部署经验,下面几个场景最值得投入 Singularity:
- 高性能计算(HPC)集群:配合 PBS/Torque/SLURM 调度系统,用户无需 root 也能运行自定义环境。
- 跨平台科学软件分发:比如将 MATLAB、Gaussian、GROMACS 等打包成 SIF 文件,直接复制到任何 Linux 节点即可执行。
- AI/ML 训练环境:结合最新 CUDA 驱动和 cuDNN,原生 GPU 支持让 PyTorch/TensorFlow 训练容器化变得极其简单。
- 老旧操作系统上的新应用:宿主是 RHEL 6 / CentOS 7,但你的应用需要 glibc 2.28+;用 Singularity 打包一个基于 Ubuntu 22.04 的容器,直接在老系统上运行。
- 安全敏感的分析流水线:加密 SIF 镜像、PGP 签名验证、安全策略文件,可以在受监管的环境中实现完整的依赖审计链。
1.6 快速验证:你的第一行 Singularity 命令
光说不练假把式。我们来跑一个实际的例子。假设你已经按照官方文档安装了 Singularity(我建议用 4.x 版本),然后拉一个现有的 Docker 镜像:
# 从 Docker Hub 拉取 Python 3.12 镜像
singularity pull docker://python:3.12-slim
# 这会生成 python_3.12-slim.sif 文件
# 直接运行 Python 解释器
singularity exec python_3.12-slim.sif python --version
看到了吗?没有 daemon,没有 sudo,当前用户直接执行。而且生成的 .sif 文件只有几十 MB(对比 Docker 解压后的多层可能超过 200 MB)。这就是「单文件分发」的威力。
如果你跟我一样是个「怀疑论者」,可以用下面命令查看容器里的 UID:
# 检查容器内与宿主机是否共享 UID
singularity exec python_3.12-slim.sif id -u
# 输出应该跟你当前用户 UID 完全一致
这个特性在集群作业调度中极度重要——因为文件系统的权限控制完全依赖于 UID。Docker 默认以 root 运行,写在挂载卷里的文件会变成 root 所有,导致其他用户无法读取。而 Singularity 默认就避免了这种问题。
singularity --version 确认版本;然后用 singularity build --sandbox ... 创建一个可写的 sandbox,进行快速调试。调试没问题后再用 singularity build 打包成只读的 SIF。这个流程可以避免 90% 以上因环境差异导致的「在我这能跑」问题。
1.7 一张图看懂本章知识结构
我把本章的核心知识点画成了 SVG 结构图。你可以把它当作一个「思维导图」来快速回顾。它覆盖了从问题起源到对比决策、再到部署落地的主线逻辑。
看完这张图,你应该对整个章节的脉络有一个全局感。记住,Singularity 的定位不是为了取代 Docker,而是为了解决特定场景下 Docker 无法优雅解决的问题。后面的章节里,我会一步步带你从安装、构建、分发到运维,把每一环都拆开讲解——但仅限实操,不灌理论水份。