参考资料:https://hsf-training.github.io/hsf-training-singularity-webpage/
动机
用 docker/apptainer 等容器工具是为了免去配置环境的痛苦。容器是封装系统环境的软件包。操作系统级别的虚拟化通过容器实现,任何在其上运行的程序都将使用容器内部隔离的上下文环境。它可以在任何系统上构建容器,只要目标平台与容器兼容,即可在任何地方执行该容器。
为什么不用 uv?
对纯 python 项目而言用 uv 管理虚拟环境是足够的,但是如果涉及到非 python 应用,例如我现在要使用 CDM 来评测 Texo,那么就涉及到 LaTeX 发行版的安装,这就比较麻烦了。
为什么不用 docker?
Docker 作为企业级容器框架的初衷是为微服务提供支持,这种方案契合行业惯用的模式:系统管理员以 root 权限启动容器引擎守护进程 daemon,并在各自容器中安装运行应用程序。这种模式与高性能计算(HPC)和高吞吐量计算(HTC)的工作流并不兼容,后者通常运行复杂应用程序时会耗尽所有可用资源,且无需任何特殊权限。运行 docker 需要 root 权限,不适合在公共的服务器集群上使用。
为什么用 apptainer?
- 无需 root 权限,运行时容器内部用户即容器外部用户,因此在高性能计算集群上能更安全的管理虚拟环境。
- 单文件容器镜像简化分发、归档、共享、使用。
- 兼容 docker 镜像,无需额外转换。
- 运行方式等同于常规应用,与 Slurm 等服务器调度框架天然兼容。
安装
首先安装 Apptainer。注意若在服务器上无 root 用户权限,可以 rootless 的方式安装,由于我的服务器上已经安装了,故略过这一步。
下载镜像 image
容器镜像是可执行文件.sif,它将应用程序或环境所需的所有组件打包在一起,如同容器的模板。容器则是镜像的运行时实例——它们是具有状态的镜像。Apptainer 可以在注册表(可搜索的镜像与容器目录库及存储库)中存储、搜索和检索镜像。用户可通过命令行界面访问其他用户构建的镜像,将其拉取下来,并在运行时转化为容器。
apptainer pull <local_image_name>.sif <remote_image_url>例如拉取 docker 环境镜像:
apptainer pull <local_image_name>.sif docker://<docker_image_name>这里把 dockerhub 上的镜像名放在 docker:// 后,apptainer 会将其识别为 docker 镜像,并将其转换为.sif格式的镜像文件。
运行
启动并退出 shell
用命令
apptainer shell <container_image>.sif将进入容器并打开一个交互式 shell,得到
Apptainer>该 shell 类似一个常规 bash shell 与进入 shell 前的宿主机身份一致。此时我们执行的所有命令都是在宿主机中的。
退出方法
Apptainer> exit或者按组合键 Ctrl+D。请注意,退出 Apptainer 镜像时所有运行进程都会被杀死。保存到绑定目录中的更改将被保留。默认情况下,容器中的其他内容都会丢失(关于可写镜像的内容我们稍后再谈)。
绑定目录
当外部目录在 Apptainer 内部也可访问时,我们称其为绑定或挂载。访问路径可能不同,但外部对其内容的任何操作在内部均可见,反之亦然。默认情况下,apptainer 将挂载用户主目录, /tmp 和 $PWD 绑定到容器中,因此在容器内可以访问这些目录。
通过 --bind 选项可以挂载额外绑定,例如
apptainer shell --bind <host_dir>:<mount_point_in_container> <container_image>.sif执行命令
exec用于在某个指定容器镜像中运行命令。例如
apptainer exec <container_image>.sif ls其输出等价于先运行
apptainer shell <container_image>.sif再在其中运行
Apptainer> ls