容器镜像格式:sandbox 与 sif 的区别与使用
两种格式,两种哲学
很多人刚开始接触 Singularity 时都会问:“我到底该用 sandbox 还是 sif?” 这个问题没有标准答案,得看场景。我个人习惯把 sandbox 看作是“开发版”,sif 看作是“发布版”。
sandbox 本质上是一个目录,里面的文件系统是解压开的,你可以直接进去改东西、装包、删文件。sif 则是一个只读的压缩包,安全、可签名、可分发。你想想看,一个几百兆的 sif 文件,传到集群上时不容易坏,而且能保证内容没有被篡改。
一句话总结:写代码用 sandbox,跑生产用 sif。
sandbox —— 随意折腾的工作台
构建 sandbox 很简单,用 --sandbox 参数就行。我在项目中第一次用 sandbox 是调试 Visium 的 Python 环境,那时候需要反复装 scVI 和 SpaGCN 的不同版本。如果每次都打 sif,构建时间至少 15 分钟,我受不了。
singularity build --sandbox ./visium_dev docker://continuumio/miniconda3:latest
然后你可以直接 shell 进去,就像在自己电脑上一样:
singularity shell --writable ./visium_dev/
注意看那个 --writable,不加的话你只能读,不能写。进去之后 apt、pip、conda 随便用,所有改动都会留在那个目录里。
注意:sandbox 目录不能放在 NFS 等网络文件系统上?其实可以,但速度会慢很多。我曾经把一个 sandbox 放在集群的共享 NAS 上,结果每次 apt install 都要卡 5 分钟。后来乖乖挪到了本地 SSD。
当你的环境调试完成后,你可能会想:这个 sandbox 能不能直接拿去用?理论上可以,但别人拿到的就是一个目录,没法验证完整性。这时候就该转成 sif 了。
sif —— 稳固的可交付件
sif 是 Singularity Image Format 的缩写,说白了就是一个只读的 squashfs 文件系统加上一些元数据。它不会在运行时被意外改动,而且支持数字签名。我通常把最终验证好的 Visium 环境打包成 sif ,然后扔到对象存储上,团队里任何人拉下来就能跑。
singularity build visium_env.sif ./visium_dev/
这条命令会把 sandbox 目录压缩成一个 sif 文件。你也可以直接从 Docker Hub 拉:
singularity build visium_env.sif docker://continuumio/miniconda3:latest
嗯,这里要注意,build sif 的时候 不能 加 --writable,因为 sif 天生就是只读的。
核心差异对照
我整理了一个表格,你直接拿着用:
| 维度 | sandbox | sif |
|---|---|---|
| 本质 | 目录(解压缩) | 单文件(压缩只读) |
| 读写能力 | 可读写(需 --writable) | 只读(不可改) |
| 构建速度 | 快(直接操作文件) | 慢(需压缩) |
| 可分发性 | 差(目录结构不便传输) | 好(一个文件,可签名) |
| 签名支持 | 不支持 | 支持(--sign) |
| 典型用途 | 开发、调试、增量修改 | 生产部署、共享、归档 |
转换与互操作
sandbox 和 sif 之间可以互相转换。我最常见的流程是:先用 build --sandbox 做一个开发环境,改完后用 build 直接打 sif。反过来,如果你拿到一个 sif 想解包看看里面装了啥,也可以用 sandbox 模式:
singularity build --sandbox ./explore sif_file.sif
不过说实话,我很少这么做。大多数时候只需要 singularity shell sif_file.sif 进去看一眼就行。
我的小技巧:如果你频繁修改一个 Visium 环境,可以用 sandbox 做日常开发,然后定期(比如每周一)转一个 sif 版本,命名带上日期,比如 visium_env_2025_04_07.sif。这样既保留了演化历史,又有一个可运行的稳定版本。
SVG:sandbox 与 sif 的使用场景流程图
下面这张图能帮你快速理解两种格式在真实项目中的流转关系。我画了一个从拉取基础镜像到最终部署的典型 pipeline:
避坑指南:我曾经踩过的坑
说实话,我之前吃过一个亏。当时在 sandbox 里装了 Visium 的全部依赖,然后直接把它拷贝到另一个服务器上,想用 singularity shell 进去跑。结果发现里面的 /tmp 目录权限不对,导致 SpaceRanger 的 pipeline 中间文件写不进去。问题出在 --writable 参数没有加,而且 sandbox 的目录权限被 scp 改变了。
从那以后我规定:sandbox 只用来调试,真正要搬环境必须打 sif。而且打 sif 的时候,最好指定一下 --section 只包含需要的部分,减少镜像体积:
singularity build --section runtime visium_env.sif ./visium_dev/
如果你在 sandbox 里跑过 apt update,这些缓存也会被打进 sif 里,没必要。可以 --section runtime 跳过 build 阶段的临时文件。
小提醒:sif 文件虽然只读,但你可以通过 --overlay 参数挂载一个可写层上去,实现“半持久化”的需求。比如 Visium 的临时结果可以写到 overlay 里,而镜像本身保持干净。
实战选择建议
最后总结一下我在 Visium 项目中的经验:
- 刚开始摸索 Visium 参数、装包 —— 用 sandbox,随时调。
- 环境稳定了,需要跑正式分析 —— 用
singularity build打 sif,加签名,上传到组里的共享目录。 - 别人要用你的镜像 —— 只给 sif,不要给 sandbox 目录(目录权限、路径依赖会出幺蛾子)。
- 需要在集群上批量提交作业 —— sif + overlay 写临时文件,一举两得。