Skip to content

Ubuntu 24.0.4 下的 apptainer 初始化与使用

约 1604 字大约 5 分钟

Linuxapptainersingularityubuntu

2026-04-20

前情提要

  • 我系“点六”服务器所装的 GNU/Linux 发行版为 Ubuntu 24.04.4 LTS,可通过以下方法验证:

    cat /etc/os-release
    
    # PRETTY_NAME="Ubuntu 24.04.4 LTS"
    # NAME="Ubuntu"
    # VERSION_ID="24.04"
    # VERSION="24.04.4 LTS (Noble Numbat)"
    # VERSION_CODENAME=noble
    # ID=ubuntu
    # ID_LIKE=debian
    # HOME_URL="https://www.ubuntu.com/"
    # SUPPORT_URL="https://help.ubuntu.com/"
    # BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
    # PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
    # UBUNTU_CODENAME=noble
    # LOGO=ubuntu-logo
  • 之前我在“点六”上使用 conda-forge 源安装的 apptainer 时,不论进行什么操作(如 shellbuild 等),都会出现以下错误:

    ERROR: Could not write info to setgroups: Permission denied
    ERROR: Error while waiting event for user namespace mappings: no event received
  • 而使用管理员(也是我)通过 apt 安装的 singularity 则一切顺利。

原因排查

  • Github 上一搜得知,原来是 Ubuntu 在 23.10 版本号后使用了 AppArmor 以增强安全性:

    Apparmor Profile (Ubuntu 23.10+)

    • Beginning with the 23.10 release and including the 24.04 LTS release, Ubuntu does not permit applications to create unprivileged user namespaces by default.

    • 从 23.10 版本开始,包括 24.04 LTS版本,Ubuntu 默认不允许应用程序创建无权限的用户命名空间。

    • If you install Apptainer from a GitHub release .deb package then an apparmor profile will be installed that permits Apptainer to create unprivileged user namespaces.

    • 如果你从 GitHub 版本.deb包安装 Apptainer,那么会安装一个 apparmor 配置文件,允许 Apptainer 创建非特权用户命名空间。

    • If you install Apptainer from source you must either configure apparmor or disable the restriction on unprivileged user namespaces. To create an apparmor profile:

    • 如果你从源头安装 Apptainer,必须配置 AppArmor 或关闭对非特权用户命名空间的限制。

  • 所以通过 apt 之外方法安装的 apptainersingularity 都会被 AppArmor 拦截,影响正常运行。必须配置 AppArmor 或关闭对非特权用户命名空间的限制。

解决办法

  • 基于 apptainer 官方的解决措施以及 这篇博客,我的解决方法如下:
    # 全面禁用非特权用户命名空间限制(写入文件以永久生效)
    echo 'kernel.apparmor_restrict_unprivileged_userns = 0' | sudo tee /etc/sysctl.d/20-apparmor-donotrestrict.conf
    sudo sysctl --load /etc/sysctl.d/20-apparmor-donotrestrict.conf
    
    # 禁用 apparmor 服务
    sudo systemctl disable --now apparmor

实际应用

  • 假设这样一个情景:你有一个 conda 虚拟环境 containertools,里面装了很多软件。
  • 实验室有另一台性能强劲的服务器,管理员在上面提前装好了 apptainer / singularity,现在需要把你的虚拟环境 containertools 移植到上面跑一个项目。
  • 可是你又不想从头配置 conda / mamba ,该怎么偷懒呢?

0. 基础准备

  • 确保虚拟环境 containertools 所在的服务器上安装有 fakerootuidmap 软件包。
  • 如果缺少可联系服务器管理员进行安装:
    # 以 Debian 系发行版为例,根据实际情况调整
    sudo apt update && sudo apt upgrade -y
    sudo apt install fakeroot uidmap fuse2fs -y

1. 打包虚拟环境

  • 使用 conda-pack 对虚拟环境 containertools 进行打包。
  • 这里我安装了若干软件进行模拟,conda-pack 可安装在 base 环境内。
    # 配置 “containertools” 虚拟环境
    #(默认你配置好了 bioconda 与 conda-forge 频道以及对应镜像源)
    mamba env create -n containertools fastp fastqc bwa bedtools
    
    # 在 base 环境安装 conda-pack 与 apptainer
    mamba install conda-pack apptainer
    
    # 使用 conda-pack 打包虚拟环境 “containertools”
    conda-pack -n containertools
    # conda-pack 的进度条结束后会在当前路径生成一个 containertools.tar.gz 压缩包

2. 构建 sif 镜像

  • 使用你喜欢的文本编辑器(例如 vim)新建一个 containertools.def 文件:

    # 使用 docker 镜像中的 ubuntu:24.04 作为基础镜像
    # 国内由于网络原因,无法直连 dockerhub 网站,所以需要配置镜像源(我这里选择了 1panel 提供的)
    Bootstrap: docker
    From: docker.1panel.live/library/ubuntu:24.04
    
    %files
        # 将刚才 conda-pack 打包好的压缩包拷贝进镜像内部
        containertools.tar.gz /opt/containertools.tar.gz
    
    %environment
        # 设置镜像内的语言环境变量,否则会有很多脚本会报 warning
        export LANG=C
        export LANGUAGE=C
        export LC_ALL=C
        # 设置环境变量,让镜像运行后默认就能找到这个环境里的软件
        export PATH=/opt/containertools/bin:$PATH
    
    %post
        # 给镜像内的 apt 换源,加快安装速度
        # 这里我选择南京大学的镜像源
        sed -E -i 's/(archive|security)\.ubuntu\.com/mirrors.nju.edu.cn/g' /etc/apt/sources.list.d/*
    
        # 安装 python,在后续的 conda-unpack 过程中会用到
        apt update && apt upgrade -y
        apt install python3 -y
    
        # 软链接一下,因为 conda-unpack 脚本的 shebang 行是 #!/usr/bin/env python
        # 而 apt 安装的 python3 默认未被指向
        ln -s /usr/bin/python3 /usr/bin/python
    
        # 创建目录并解压环境
        mkdir -p /opt/containertools
        tar -xzf /opt/containertools.tar.gz -C /opt/containertools
        rm /opt/containertools.tar.gz
    
        # 激活虚拟环境 containertools 中的 conda-unpack 脚本(修复路径)
        /opt/containertools/bin/conda-unpack
    
    %runscript
        # 默认执行命令
        exec "$@"
  • 开始构建吧~

    apptainer build --fakeroot containertools.sif containertools.def
    # 耐心等待ing...
    # 网速给力的情况下应该挺快的,我测试时整个 build 阶段就花了40多秒
    # 
    # time apptainer build --fakeroot containertools.sif containertools.def
    # real	0m41.421s
    # user	1m26.779s
    # sys	0m5.683s

3. 使用 sif 镜像

3.1 交互模式

  • 将上一步生成的 containertools.sif 通过 scp / sftp 等方法上传到另一台服务器上,就可以运行啦~
    # 在另一台服务器上
    apptainer shell containertools.sif
    
    # 检查版本与安装路径
    # Apptainer> fastp --version
    # fastp 1.3.2
    
    # Apptainer> fastqc --version
    # FastQC v0.12.1
    
    # Apptainer> bedtools --version
    # bedtools v2.31.1
    
    # Apptainer> which bwa
    # /opt/containertools/bin/bwa
  • apptainer 会默认将你的主目录挂载到镜像内部,如果想要在镜像里使用除主目录外的路径,需要添加 --bind 参数。
  • ⚠️ 注意:冒号左侧的为宿主机中的真实路径 /public/workspace/shaojf/Course/NGS/Reference,冒号右侧的为镜像内映射的虚拟路径 /ref
    # 假如我想挂载主目录中邵老师下载好的参考基因文件到镜像内的/ref路径
    apptainer shell \
    --bind /public/workspace/shaojf/Course/NGS/Reference:/ref \
    containertools.sif
    
    # 随便看看人类 hg38 参考基因组的前几行
    head -5 /ref/Ensembl/Homo_sapiens.GRCh38.dna.chromosome.22.fa
  • 使用完 apptainer 镜像后, 按下 Ctrl + D 或输入 exit 后回车退出镜像交互模式,可回到宿主机。

3.2 非交互模式

  • 除了交互模式,apptainer 也像 conda 那样支持免激活运行(详见我的上一个博客:conda run
  • 非交互模式对于编写脚本或流程时调用多个虚拟环境内的不同软件会更加友好~
    # 检查 fastp 的版本与安装路径
    apptainer exec \
    --bind /public/workspace/shaojf/Course/NGS/Reference:/ref \
    containertools.sif \
    fastp --version
    # fastp 1.3.2
    
    apptainer exec \
    --bind /public/workspace/shaojf/Course/NGS/Reference:/ref \
    containertools.sif \
    which fastp
    # /opt/containertools/bin/fastp
    
    # 随便看看人类 hg38 参考基因组的前几行
    apptainer exec \
    --bind /public/workspace/shaojf/Course/NGS/Reference:/ref \
    containertools.sif \
    head -5 /ref/Ensembl/Homo_sapiens.GRCh38.dna.chromosome.22.fa