一、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 环境中。

核心原则:Singularity 是「以用户为中心的容器」——不要求管理员权限、不需要 daemon、直接利用用户自己的 UID/GID 运行。这跟 Docker 的「以进程为中心的容器」有本质区别。

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 生态深度整合
个人经验:如果你在对安全性要求极高的生产环境部署,我建议使用 4.x 版本。尤其是加密 SIF 镜像和基于 PGP 签名的验证机制,在合规场景下是不可替代的。我曾经在某个涉密项目中,因为使用了未加密的容器镜像,被安全审计卡了两周。后来迁到 Singularity 4.x 才解决问题。

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 与外部一致
避坑指南:我曾经部署了一个集群,一开始图方便用 Docker 作为运行时。然后发现每次作业排队启动时,必须为每个容器创建一个独立的网络 namespace,这导致了 IP 池被迅速耗尽;而且 SLURM 作业被中断后残留的容器得不到清理。后来全部迁移到 Singularity,直接用 singularity exec 替换 docker run,问题迎刃而解。所以如果你的环境是 HPC/ML 训练/科学计算,直接用 Singularity 可以少踩 80% 的坑。

1.5 Singularity 的适用场景

根据我实际部署经验,下面几个场景最值得投入 Singularity:

  1. 高性能计算(HPC)集群:配合 PBS/Torque/SLURM 调度系统,用户无需 root 也能运行自定义环境。
  2. 跨平台科学软件分发:比如将 MATLAB、Gaussian、GROMACS 等打包成 SIF 文件,直接复制到任何 Linux 节点即可执行。
  3. AI/ML 训练环境:结合最新 CUDA 驱动和 cuDNN,原生 GPU 支持让 PyTorch/TensorFlow 训练容器化变得极其简单。
  4. 老旧操作系统上的新应用:宿主是 RHEL 6 / CentOS 7,但你的应用需要 glibc 2.28+;用 Singularity 打包一个基于 Ubuntu 22.04 的容器,直接在老系统上运行。
  5. 安全敏感的分析流水线:加密 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 容器化部署实践 · 第1章 知识结构 Singularity 核心定位 传统容器问题 需要 root / daemon 与调度系统冲突 设计理念 单文件 SIF 格式 UID 与宿主一致 兼容 Docker 镜像 适用场景 HPC / 超算集群 跨 OS 兼容环境 安全敏感管线 Docker vs Singularity 版本迭代历史 第一个容器运行 左:为什么需要 Singularity → 中:它的设计哲学 → 右:在什么场景用 核心收益:无 root、无 daemon、单文件分发、原生 GPU/MPI、信任继承

看完这张图,你应该对整个章节的脉络有一个全局感。记住,Singularity 的定位不是为了取代 Docker,而是为了解决特定场景下 Docker 无法优雅解决的问题。后面的章节里,我会一步步带你从安装、构建、分发到运维,把每一环都拆开讲解——但仅限实操,不灌理论水份。

一句话总结:Singularity 是容器的「HPC 版」——以用户为中心、无 daemon、单文件、原生加速,解决 Docker 在科学计算和安全合规场景中的所有短板。