容器镜像

无论您是想与不使用 Spack 的人共享应用程序、在运行容器镜像的云服务上进行部署,还是将工作负载迁移到高性能计算(HPC)集群,容器都是打包和分发软件的一种有效方式。

Spack 提供了两种截然不同的创建容器镜像的范式,每种范式都有其独特的优势。您可以将主机系统上已经构建好的软件包导出为容器镜像,也可以生成传统的配方文件(Dockerfile 或 Singularity 定义文件),以便在容器内从零开始构建软件。

Spack 容器镜像创建方法对比

容器镜像导出

配方生成

目的

将主机系统上的现有安装导出为容器镜像

运行 spack install,在容器构建过程中从源码构建软件

Spack 命令

spack buildcache push

spack containerize

可重复性

有限:依赖于主机系统

高:受控的构建环境

输入

已安装的 Spack 软件包或环境

spack.yaml 文件

速度

较快:复制现有二进制文件

较慢:通常从源码构建

故障排查

构建问题在主机上解决,调试更简单

构建问题必须在容器构建过程中解决

构建工具

Docker、Podman、Singularity 或类似工具

权限

无(无需 root)

可能需要提升权限,具体取决于容器构建工具(需要 root)

输出目标

兼容 OCI 的注册表

本地 Docker 或 Singularity 镜像

将 Spack 安装导出为容器镜像

此命令

spack buildcache push [--base-image BASE_IMAGE] [--tag TAG] mirror [specs...]

创建并将容器镜像推送到兼容 OCI 的容器注册表,其中 mirror 参数指定了注册表(见下文)。

与其将此命令视为“构建容器”,不如将其视为将工作软件栈归档为可移植镜像的过程。

以这种方式创建的容器镜像非常精简:它们仅包含指定规范的运行时依赖项、基础镜像,不包含其他任何内容。Spack 本身包含在生成的镜像中。

参数如下

--base-image BASE_IMAGE

指定用于容器的基础镜像。这应该是一个精简的 Linux 发行版,其 libc 与主机系统兼容。例如,如果您的主机系统是 Ubuntu 22.04,则可以使用 ubuntu:22.04ubuntu:24.04 或更新版本:假设 ABI 兼容,容器镜像中的 libc 必须至少达到主机系统的版本。只要 libc 兼容,完全使用不同的 Linux 发行版也完全没有问题。

--tag TAG

指定要使用的容器镜像标签。该标签用于包含命令行中指定的所有规范的镜像。

mirror 参数

可以是已配置的 OCI 注册表镜像名称(在 mirrors.yaml 中),也可以是指定注册表和镜像名称的 URL。

  • 推送到远程注册表时,您通常会从 Spack 配置中指定注册表的名称

  • 推送到本地注册表时,只需指定类似 oci+https://:5000/[image] 的 URL 即可,其中 [image] 是要创建的镜像名称,oci+http:// 表示该注册表不支持 HTTPS。

specs... 参数

是要包含在镜像中的 Spack 规范列表。这些是已经由 Spack 安装的软件包。当激活 Spack 环境时,只有环境中的软件包会被包含在镜像中。如果没有提供规范且激活了 Spack 环境,则环境中的所有软件包都会被包含。

Spack 将每个独立的依赖项发布为单独的镜像层,这使得具有重叠依赖项的镜像能够进行高效的存储和传输。

注意

Docker 的 overlayfs2 存储驱动程序限制为 128 层,超过此限制时,拉取镜像可能会产生 max depth exceeded(超过最大深度)错误。当从较大的环境或具有许多依赖项的软件包导出容器镜像时,您可能会达到此限制。有替代驱动程序可以绕过此限制。

spack buildcache push --base-image ... 命令具有双重用途

  1. 它使容器镜像可用于 Docker 和 Podman 等容器运行时。

  2. 它使相同的二进制文件可作为 spack install构建缓存使用。

容器注册表

spack buildcache push 命令直接将容器镜像导出到兼容 OCI 的容器注册表,例如 Docker Hub、GitHub 容器注册表 (GHCR)、Amazon ECR、Google GCR、Azure ACR 或私有注册表。

这些服务需要身份验证,这是通过 spack mirror add 命令配置的

$ spack mirror add \
      --oci-username-variable REGISTRY_USER \
      --oci-password-variable REGISTRY_TOKEN \
      example-registry \
      oci://example.com/name/image

这会在您的 mirrors.yaml 配置文件中注册一个名为 example-registry 的镜像库,该镜像库与容器注册表和镜像 example.com/name/image 相关联。然后可以通过名称引用该注册表,例如 spack buildcache push example-registry ...

URL 中的 oci:// 方案表示这是一个支持 HTTPS 的兼容 OCI 的注册表。如果您仅指定 oci://name/image,Spack 将假设该注册表托管在 Docker Hub 上。

--oci-username-variable--oci-password-variable 选项用于指定将用于向注册表进行身份验证的环境变量名称。Spack 不会将您的凭据存储在配置文件中;它要求您在运行 spack buildcache push 命令之前在 shell 中设置相应的环境变量。

$ REGISTRY_USER=user REGISTRY_TOKEN=token spack buildcache push ...

另请参阅

注册表密码通常是在注册表网站或命令行工具上生成的个人访问令牌 (PAT)。在流行容器注册表的身份验证一节中,我们列出了流行注册表的具体示例。

如果您无法访问远程注册表,或者希望在本地试验容器镜像,可以在您的机器上运行本地注册表并让 Spack 推送到该注册表。这就像在后台运行官方注册表镜像一样简单

$ docker run -d -p 5000:5000 --name registry registry

在这种情况下,无需配置命名镜像库,您只需使用 oci+https://:5000/[image] 通过 URL 进行引用即可,其中 [image] 是要创建的镜像名称,oci+http:// 表示该注册表不支持 HTTPS。

示例 1:推送选定的规范作为容器镜像

假设我们已经安装了 python@3.13cmake@3(由 Spack 安装),并且我们想将它们作为一个组合容器镜像 software_stack:latest 推送到本地注册表。

首先,我们确认这些规范确实已安装

$ spack find --long python@3.13 cmake@3

-- linux-ubuntu24.04-zen2 / %c,cxx=gcc@13.3.0 -------------------
scpgv2h cmake@3.31.8  n54tvjw python@3.13.5

由于这些是系统上仅有的安装,我们可以简单地通过它们的规范字符串引用它们。如果有多个安装,我们可以使用 python/n54tvjwcmake/scpgv2h 通过哈希值唯一地引用它们。

现在,我们使用 spack buildcache push 将这些软件包作为容器镜像发布,并使用 ubuntu:24.04 作为基础镜像

$ spack buildcache push \
      --base-image ubuntu:24.04 \
      --tag latest \
      oci+https://:5000/software_stack \
      python@3.13 cmake@3

现在可以使用 Docker 或任何其他兼容 OCI 的容器运行时拉取并运行它们

$ docker run -it localhost:5000/software_stack:latest
root@container-id:/# python3 --version
Python 3.13.5
root@container-id:/# cmake --version
cmake version 3.31.8

示例 2:推送整个 Spack 环境作为容器镜像

在此示例中,我们展示如何将已安装的 Spack 环境导出为容器镜像并将其推送到远程注册表。

# Create and install an environment
$ spack env create .
$ spack -e . add python@3.13 cmake@3
$ spack -e . install

# Configure a remote registry
$ spack -e . mirror add \
      --oci-username-variable REGISTRY_USER \
      --oci-password-variable REGISTRY_TOKEN \
      container-registry \
      oci://example.com/name/image

# Push the image
$ REGISTRY_USER=user REGISTRY_TOKEN=token \
  spack -e . buildcache push \
      --update-index \
      --base-image ubuntu:24.04 \
      --tag my_env \
      container-registry

生成的容器镜像可以按如下方式运行

$ docker run -it example.com/name/image:my_env
root@container-id:/# python3 --version
Python 3.13.5
root@container-id:/# cmake --version
cmake version 3.31.8

使用 Spack 环境的优势在于,在推送镜像时,我们不必在命令行上指定各个规范。使用环境时,所有根规范及其运行时依赖项都会包含在容器镜像中。

如果您在激活环境的情况下在 spack buildcache push 中指定了规范,则只有环境中的那些匹配规范会被包含在镜像中。

为 Docker 和 Singularity 生成配方

除了将现有安装导出为容器镜像外,Spack 还可以为容器镜像生成配方。如果您想在沙箱环境中运行 Spack 本身,而不是在主机系统上运行,这将非常有用。

此方法要求您的系统上安装了 Docker 或 Singularity 等容器运行时,并且只能使用 Spack 环境。

由于配方比

COPY spack.yaml /environment
RUN spack -e /environment install

Spack 提供了一个命令来生成可定制的容器镜像配方。自定义项包括最小化镜像大小、使用系统软件包管理器在基础镜像中安装软件包,以及设置适当的入口点以运行镜像。

快速入门

假设有一个如下所示的 Spack 环境

spack:
  specs:
  - gromacs+mpi
  - mpich

从中生成 Dockerfile 就像切换到 spack.yaml 文件所在的目录并运行以下命令一样简单

$ spack containerize > Dockerfile

创建的 Dockerfile 使用多阶段构建和其他技术来最小化最终镜像的大小

# Build stage with Spack pre-installed and ready to be used
FROM spack/ubuntu-jammy:develop AS builder


# What we want to install and how we want to install it
# is specified in a manifest file (spack.yaml)
RUN mkdir -p /opt/spack-environment && \
set -o noclobber \
&&  (echo spack: \
&&   echo '  specs:' \
&&   echo '  - gromacs+mpi' \
&&   echo '  - mpich' \
&&   echo '  concretizer:' \
&&   echo '    unify: true' \
&&   echo '  config:' \
&&   echo '    install_tree:' \
&&   echo '      root: /opt/software' \
&&   echo '  view: /opt/views/view') > /opt/spack-environment/spack.yaml

# Install the software, remove unnecessary deps
RUN cd /opt/spack-environment && spack env activate . && spack install --fail-fast && spack gc -y

# Strip all the binaries
RUN find -L /opt/views/view/* -type f -exec readlink -f '{}' \; | \
    xargs file -i | \
    grep 'charset=binary' | \
    grep 'x-executable\|x-archive\|x-sharedlib' | \
    awk -F: '{print $1}' | xargs strip

# Modifications to the environment that are necessary to run
RUN cd /opt/spack-environment && \
    spack env activate --sh -d . > activate.sh


# Bare OS image to run the installed executables
FROM ubuntu:22.04

COPY --from=builder /opt/spack-environment /opt/spack-environment
COPY --from=builder /opt/software /opt/software
COPY --from=builder /opt/views /opt/views

RUN { \
      echo '#!/bin/sh' \
      && echo '.' /opt/spack-environment/activate.sh \
      && echo 'exec "$@"'; \
    } > /entrypoint.sh \
&& chmod a+x /entrypoint.sh \
&& ln -s /opt/views/view /opt/view


ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "/bin/bash" ]

然后,镜像本身可以使用任何适合该任务的工具以通常的方式进行构建和运行。例如,如果我们决定使用 Docker

$ spack containerize > Dockerfile
$ docker build -t myimage .
[ ... ]
$ docker run -it myimage

下面各节将详细讨论生成配方所涉及的各种组件及其配置。

Spack 官方容器镜像

预装了 Spack 的容器镜像可在 Docker HubGitHub 容器注册表 上获得。这些镜像基于流行的发行版,并据此命名(例如,基于 ubuntu:24.04 的 Spack 镜像为 spack/ubuntu-noble)。

下表总结了可用的基础镜像及其对应的 Spack 镜像

支持的基础容器镜像

基础发行版

基础镜像

Spack 镜像

Ubuntu 20.04

ubuntu:20.04

spack/ubuntu-focal

Ubuntu 22.04

ubuntu:22.04

spack/ubuntu-jammy

Ubuntu 24.04

ubuntu:24.04

spack/ubuntu-noble

CentOS Stream 9

quay.io/centos/centos:stream9

spack/centos-stream9

openSUSE Leap

opensuse/leap

spack/leap15

Amazon Linux 2

amazonlinux:2

spack/amazon-linux

AlmaLinux 8

almalinux:8

spack/almalinux8

AlmaLinux 9

almalinux:9

spack/almalinux9

Rocky Linux 8

rockylinux:8

spack/rockylinux8

Rocky Linux 9

rockylinux:9

spack/rockylinux9

Fedora Linux 39

fedora:39

spack/fedora39

Fedora Linux 40

fedora:40

spack/fedora40

所有容器镜像都标记了它们所包含的 Spack 版本。

Spack 容器镜像标签

标签

含义

<image>:latest

Spack 的最新稳定版本

<image>:1

Spack 的最新 1.x.y 版本

<image>:1.0

Spack 的最新 1.0.y 版本

<image>:1.0.2

特定的 1.0.2 Spack 版本

<image>:develop

Spack 的最新开发版本

这些镜像供任何人使用,并处理了在容器内设置 Spack 所需的所有重复性任务。Spack 生成的容器配方将它们作为其 build 阶段的默认基础镜像,尽管也可以选择使用用户提供的自定义基础镜像以适应复杂的用例。

配置容器配方

任何 Spack 环境都可以用于自动生成容器配方。对于基础镜像或镜像中使用的 Spack 版本等内容,提供了合理的默认值。如果需要更精细的调整,可以通过在环境的 container 属性下添加相关的元数据来实现。

spack:
  specs:
  - gromacs+mpi
  - mpich

  container:
    # Select the format of the recipe e.g. docker,
    # singularity or anything else that is currently supported
    format: docker

    # Sets the base images for the stages where Spack builds the
    # software or where the software gets installed after being built.
    images:
      os: "almalinux:9"
      spack: develop

    # Whether or not to strip binaries
    strip: true

    # Additional system packages that are needed at runtime
    os_packages:
      final:
      - libgomp

    # Labels for the image
    labels:
      app: "gromacs"
      mpi: "mpich"

有关可用选项的详细说明,请参阅配置参考一节。

设置基础镜像

images 子部分用于选择 Spack 构建软件的镜像以及安装构建软件的镜像。此属性可以以不同的方式设置,具体使用哪种方式取决于手头的用例。

使用 Dockerhub 的 Spack 官方镜像

要生成一个使用 Spack 官方 Docker 镜像构建软件,并使用相应的官方操作系统镜像安装构建出的软件的配方,用户只需指定:

  1. images:os 下的操作系统

  2. images:spack 下的 Spack 版本

允许使用这两个值的任意组合,只要它能映射到Spack 官方容器镜像中讨论的镜像之一即可。例如,以下 spack.yaml

spack:
  specs:
  - gromacs+mpi
  - mpich

  container:
    images:
      os: almalinux:9
      spack: "1.0"

在分别构建和安装软件的阶段中,使用了 spack/almalinux9:1.0almalinux:9

# Build stage with Spack pre-installed and ready to be used
FROM spack/almalinux9:1.0 AS builder


# What we want to install and how we want to install it
# is specified in a manifest file (spack.yaml)
RUN mkdir -p /opt/spack-environment && \
set -o noclobber \
&&  (echo spack: \
&&   echo '  specs:' \
&&   echo '  - gromacs+mpi' \
&&   echo '  - mpich' \
&&   echo '  concretizer:' \
&&   echo '    unify: true' \
&&   echo '  config:' \
&&   echo '    install_tree:' \
&&   echo '      root: /opt/software' \
&&   echo '  view: /opt/views/view') > /opt/spack-environment/spack.yaml

# ...

# Bare OS image to run the installed executables
FROM quay.io/almalinuxorg/almalinux:9

COPY --from=builder /opt/spack-environment /opt/spack-environment
COPY --from=builder /opt/software /opt/software
COPY --from=builder /opt/views /opt/views

RUN { \
      echo '#!/bin/sh' \
      && echo '.' /opt/spack-environment/activate.sh \
      && echo 'exec "$@"'; \
    } > /entrypoint.sh \
&& chmod a+x /entrypoint.sh \
&& ln -s /opt/views/view /opt/view


ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "/bin/bash" ]

这是选择基础镜像的最简单可用方法,我们建议尽可能使用它。不过,在某些情况下,使用 Spack 官方镜像不足以满足生产需求。在这些情况下,用户可以扩展配方,以在某个固定的 Spack 版本上进行引导,或者手动选择配方起始的基础镜像,我们接下来将看到。

使用 Spack 的引导(Bootstrap)阶段

在某些情况下,用户可能希望固定 Spack 使用的 commit SHA,以确保以后的可重复性,或者从 Spack 官方仓库的分支开始,以尝试开发早期的错误修复或特性。通过在 spack.yaml 文件中稍微更详细地指定有关 Spack 的信息,可以实现这一点。

images:
  os: amazonlinux:2
  spack:
    # URL of the Spack repository to be used in the container image
    url: <to-use-a-fork>
    # Either a commit SHA, a branch name, or a tag
    ref: <sha/tag/branch>
    # If true, turn a branch name or a tag into the corresponding commit
    # SHA at the time of recipe generation
    resolve_sha: <true/false>

url 指定克隆 Spack 的 URL,默认为 https://github.com/spack/spackref 属性可以是 commit SHA、分支名称或标签。在这种情况下,默认值是使用 develop 分支,但在未来可能会更改为指向最新的稳定版本。最后,resolve_sha 会在生成配方时将分支名称或标签转换为相应的 commit SHA,以便在以后更好地重现结果。

可用于引导 Spack 的操作系统列表可以通过以下方式获取:

$ spack containerize --list-os
==> The following operating systems can be used to bootstrap Spack:
alpine:3 amazonlinux:2 fedora:40 fedora:39 rockylinux:9 rockylinux:8 almalinux:9 almalinux:8 centos:stream9 opensuse/leap:15 nvidia/cuda:11.2.1 ubuntu:24.04 ubuntu:22.04 ubuntu:20.04

注意

resolve_sha 选项在底层使用 git rev-parse,因此在生成配方之前,需要将相应的 Spack 仓库检出到临时文件夹中。由于有这一额外步骤,设置此选项为 true 时,配方生成可能需要更长时间。

使用用户提供的自定义镜像

例如,考虑构建用于 CUDA 应用程序的生产级镜像。最好的策略可能是基于供应商提供的镜像进行构建,并将 CUDA 视为外部软件包。

Spack 目前不提供以这种方式配置 CUDA 的官方镜像,但用户可以自行构建,然后配置环境以显式拉取它。这要求用户:

  1. images:build 下指定用于构建软件的镜像

  2. images:final 下指定用于安装已构建软件的镜像

像下面这样的 spack.yaml

spack:
  specs:
  - gromacs@2019.4+cuda build_type=Release
  - mpich
  - fftw precision=float
  packages:
    cuda:
      buildable: false
      externals:
      - spec: cuda%gcc
        prefix: /usr/local/cuda

  container:
    images:
      build: custom/cuda-13.0.1-ubuntu22.04:latest
      final: nvidia/cuda:13.0.1-base-ubuntu22.04

例如会生成如下的 Dockerfile

# Build stage with Spack pre-installed and ready to be used
FROM custom/cuda-13.0.1-ubuntu22.04:latest AS builder


# What we want to install and how we want to install it
# is specified in a manifest file (spack.yaml)
RUN mkdir -p /opt/spack-environment && \
set -o noclobber \
&&  (echo spack: \
&&   echo '  specs:' \
&&   echo '  - gromacs@2019.4+cuda build_type=Release' \
&&   echo '  - mpich' \
&&   echo '  - fftw precision=float' \
&&   echo '  packages:' \
&&   echo '    cuda:' \
&&   echo '      buildable: false' \
&&   echo '      externals:' \
&&   echo '      - spec: cuda%gcc' \
&&   echo '        prefix: /usr/local/cuda' \
&&   echo '' \
&&   echo '  concretizer:' \
&&   echo '    unify: true' \
&&   echo '  config:' \
&&   echo '    install_tree:' \
&&   echo '      root: /opt/software' \
&&   echo '  view: /opt/views/view') > /opt/spack-environment/spack.yaml

# Install the software, remove unnecessary deps
RUN cd /opt/spack-environment && spack env activate . && spack install --fail-fast && spack gc -y

# Strip all the binaries
RUN find -L /opt/views/view/* -type f -exec readlink -f '{}' \; | \
    xargs file -i | \
    grep 'charset=binary' | \
    grep 'x-executable\|x-archive\|x-sharedlib' | \
    awk -F: '{print $1}' | xargs strip

# Modifications to the environment that are necessary to run
RUN cd /opt/spack-environment && \
    spack env activate --sh -d . > activate.sh


# Bare OS image to run the installed executables
FROM nvidia/cuda:13.0.1-base-ubuntu22.04

COPY --from=builder /opt/spack-environment /opt/spack-environment
COPY --from=builder /opt/software /opt/software
COPY --from=builder /opt/views /opt/views

RUN { \
      echo '#!/bin/sh' \
      && echo '.' /opt/spack-environment/activate.sh \
      && echo 'exec "$@"'; \
    } > /entrypoint.sh \
&& chmod a+x /entrypoint.sh \
&& ln -s /opt/views/view /opt/view


ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "/bin/bash" ]

其中两个阶段的基础镜像都是完全自定义的。

这种选择基础镜像的第二种模式比仅选择操作系统和 Spack 版本更灵活,但也要求更高。用户可能需要自己生成基础镜像,并且确保以下内容也是他们的责任:

  1. Spack 在 build 阶段可用,并已正确设置为安装所需的软件

  2. build 阶段产生的工件可以在 final 阶段执行

因此,我们不建议在可以通过上述第一种简化模式覆盖的情况下使用它。

Singularity 定义文件

除了生成 Dockerfile 格式的配方外,Spack 还可以通过更改 format 属性的值来生成 Singularity 定义文件

$ cat spack.yaml
spack:
  specs:
  - hdf5~mpi
  container:
    format: singularity

$ spack containerize > hdf5.def
$ sudo singularity build hdf5.sif hdf5.def

从 Spack 生成的配方构建 SIF(Singularity 镜像格式)镜像所需的 Singularity 最低版本是 3.5.3

扩展 Jinja2 模板

Spack 可以生成的 Dockerfile 和 Singularity 定义文件基于几个 Jinja2 模板,这些模板根据正在进行容器化的 Spack 环境进行渲染。即使 Spack 仅通过为配置选项设置适当的值就允许进行大量的自定义,但这有时还不够。

在这些情况下,用户可以直接扩展 Spack 用于渲染镜像的模板,例如,设置额外的环境变量,或者在构建的给定阶段之前或之后执行特定的操作。以如下结构为例

$ tree /opt/environment
/opt/environment
├── data
│     └── data.csv
├── spack.yaml
├── data
└── templates
    └── container
        └── CustomDockerfile

其中同时包含自定义模板扩展和 Spack 环境清单文件。要使用自定义模板,Spack 环境必须注册包含它的目录,并根据 container 配置声明其使用

spack:
  specs:
  - hdf5~mpi
  concretizer:
    unify: true
  config:
    template_dirs:
    - /opt/environment/templates
  container:
    format: docker
    depfile: true
    template: container/CustomDockerfile

模板扩展可以覆盖两个块,分别名为 build_stagefinal_stage,类似于下例

/opt/environment/templates/container/CustomDockerfile
{% extends "container/Dockerfile" %}
{% block build_stage %}
RUN echo "Start building"
{{ super() }}
{% endblock %}
{% block final_stage %}
{{ super() }}
COPY data /share/myapp/data
{% endblock %}

通过运行以下命令生成 Dockerfile

$ spack -e /opt/environment containerize

请注意,必须激活 Spack 环境才能让 Spack 读取模板。生成的配方包含我们在模板扩展中添加的两条额外指令

# Build stage with Spack pre-installed and ready to be used
FROM spack/ubuntu-jammy:develop AS builder

RUN echo "Start building"

# What we want to install and how we want to install it
# is specified in a manifest file (spack.yaml)
RUN mkdir -p /opt/spack-environment && \
set -o noclobber \
&&  (echo spack: \
&&   echo '  specs:' \
&&   echo '  - hdf5~mpi' \
&&   echo '  concretizer:' \
&&   echo '    unify: true' \
&&   echo '  config:' \
&&   echo '    template_dirs:' \
&&   echo '    - /tmp/tmp.xvyLqAZpZg' \
&&   echo '    install_tree:' \
&&   echo '      root: /opt/software' \
&&   echo '  view: /opt/views/view') > /opt/spack-environment/spack.yaml

# Install the software, remove unnecessary deps
RUN cd /opt/spack-environment && spack env activate . && spack concretize && spack env depfile -o Makefile && make -j $(nproc) && spack gc -y

# Strip all the binaries
RUN find -L /opt/views/view/* -type f -exec readlink -f '{}' \; | \
    xargs file -i | \
    grep 'charset=binary' | \
    grep 'x-executable\|x-archive\|x-sharedlib' | \
    awk -F: '{print $1}' | xargs strip

# Modifications to the environment that are necessary to run
RUN cd /opt/spack-environment && \
    spack env activate --sh -d . > activate.sh



# Bare OS image to run the installed executables
FROM ubuntu:22.04

COPY --from=builder /opt/spack-environment /opt/spack-environment
COPY --from=builder /opt/software /opt/software
COPY --from=builder /opt/views /opt/views

RUN { \
      echo '#!/bin/sh' \
      && echo '.' /opt/spack-environment/activate.sh \
      && echo 'exec "$@"'; \
    } > /entrypoint.sh \
&& chmod a+x /entrypoint.sh \
&& ln -s /opt/views/view /opt/view



COPY data /share/myapp/data
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "/bin/bash" ]

配置参考

下表描述了当前支持用于自定义容器配方生成的所有配置选项

spack.yamlcontainer 部分的常规配置选项

选项名称

描述

允许的值

必需

format

配方的格式

dockersingularity

depfile

是否使用 depfile 进行安装

True 或 False(默认)

images:os

用作镜像基础的操作系统

请参阅 支持的基础容器镜像

是(如果使用受限的基础镜像选择)

images:spack

build 阶段中使用的 Spack 版本

base:image 的有效标签

是(如果使用受限的基础镜像选择)

images:spack:url

克隆 Spack 的存储库

Spack 的任何分支

images:spack:ref

Spack 检出的引用

提交 SHA、分支名称或标签

images:spack:resolve_sha

spack.yaml 中的分支和标签解析为生成的配方中的提交

True 或 False(默认:False)

images:build

build 阶段中使用的镜像

任何有效的容器镜像

是(如果使用自定义的基础镜像选择)

images:final

final 阶段(运行时)中使用的镜像

任何有效的容器镜像

是(如果使用自定义的基础镜像选择)

strip

是否剥离(strip)二进制文件

true(默认)或 false

os_packages:command

用于管理系统软件包的工具

apt, yum, dnf, dnf_epel, zypper, apk, yum_amazon

仅适用于自定义基础镜像

os_packages:update

是否更新可用软件包列表

True 或 False(默认:True)

os_packages:build

构建时所需的系统软件包

当前 OS 的有效软件包

os_packages:final

运行时所需的系统软件包

当前 OS 的有效软件包

labels

标记镜像的标签

键值字符串对

Singularity 特有的配置选项

选项名称

描述

允许的值

必需

singularity:runscript

%runscript 的内容

任何有效的脚本

singularity:startscript

%startscript 的内容

任何有效的脚本

singularity:test

%test 的内容

任何有效的脚本

singularity:help

镜像的描述

描述字符串

最佳实践

MPI

由于对 Fortran 的依赖,而它是 Spack 默认实现的 OpenMPI,请考虑将 gfortran 添加到 apt-get install 列表中。

OpenMPI 的较新版本要求您在 Docker 内以 root 用户身份启动时,将 --allow-run-as-root 传递给您的 mpirun 调用。

对于在 HPC 集群上的执行,将 Docker 镜像导入 Singularity 以便使用外部 MPI 启动程序可能会有所帮助。否则,也可以将 openssh-server 添加到 apt-get install 列表中。

CUDA

从 CUDA 9.0 开始,NVIDIA 提供了基于 Ubuntu 的精简 CUDA 镜像。请参阅他们的说明。避免通过添加(例如)双重安装 CUDA

packages:
  cuda:
    externals:
    - spec: "cuda@9.0.176 arch=linux-ubuntu16-x86_64 %gcc@5.4.0"
      prefix: /usr/local/cuda
    buildable: false

到您的 spack.yaml 中。

用户要么需要 nvidia-docker,或者例如使用 Singularity 来执行设备内核。

Windows 和 macOS 上的 Docker

在 macOS 和 Windows 上,Docker 运行在默认分配内存不多的管理程序上,一些 Spack 软件包可能会因为内存不足而无法构建。为了解决这个问题,请考虑配置您的 Docker 安装以使用更多的主机内存。在某些情况下,您还可以通过在 config.yaml 中限制并行度来减轻并行构建的内存压力。

config:
  build_jobs: 2