弹性容器集群使用Spack
概述
Spack是一个多平台包管理器,用于构建和安装软件的多个版本和配置。它适用于 Linux, macOS, Windows 和 许多超级计算机。 Spack是非破坏性的,安装软件包的新版本不会破坏现有安装,因此同一包的配置可以共存。 Spack 提供了一个简单的 “spec” 语法,允许用户指定版本 和配置选项。包文件是用纯 Python 编写的,并且 规范允许包作者为许多不同的 build 的 build 中。使用 Spack,您可以按照所有想要的方式构建软件。
如果将软件安装在容器中系统默认路径中,那么容器重启后,除了一些预装在容器镜像中的基础软件外,其他内容将全部丢失。推荐使用 Spack 软件将重要的软件安装在指定持久化目录中。
本指南以Slurm为例,演示下在容器内使用Spack 请按照以下步骤完成演示。
前置条件
- 已在弹性容器集群中启动了一个容器
安装 Spack
Spack 的安装比较简单,在容器内下载spack安装包,解压到指定目录即可。下载spack
如想安装其他版本,请参考 https://github.com/spack/spack/releases
下载
mkdir -p ~/software/src
# 下载 spack 安装包,复制上面下载连接替换[spack-link]
wget -O ~/software/src/spack-0.22.3.tar.gz [spack—link]
安装
mkdir ~/opt
tar -C ~/opt -xzf ~/software/src/spack-0.22.3.tar.gz
ln -snf ~/opt/spack-0.22.3 ~/opt/spack
退出容器,重新进入容器
exit
kubectl exec -it slurm-client-8549c7576f-99vg9 -- su - user
用户的登录脚本 (.profile
) 中内置了设置 Spack 的代码,因此退出控制台并重新登录,系统输出:
==> Created environment default in: /home/user/opt/spack-trunk/environments/default
==> Activate with: spack env activate default
Spack is installed and default environment is activated.
在以上输出过程中,Spack 进行了一些初始化操作,因此需要等待一段时间,在以后的登录过程中不再有初始化过程。
输出信息中显示系统中安装了 Spack 并且激活了 default 环境。
在 ~/.spack
目录下预置了 Spack 的配置文件,使得 Spack 本身安装在 ~/opt/spack
目录下,Spack 安装的软件包和环境等位于 ~/opt/spack-trunk
目录下。
输入以下命令可以查看已激活的 Spack 环境:
spack env status
输出信息:
==> In environment default
这表明当前激活的环境为 default.
Spack 引导 (bootstrap)
Spack 本身需要一些软件来协助完成其他软件包的管理动作,安装这些软件的过程称之为引导。
用以下命令检查引导状态:
spack bootstrap status
在引导完成之前可能输出如下:
Spack v0.22.2 - python@3.10
[FAIL] Core Functionalities
[B] MISSING "clingo": required to concretize specs
[FAIL] Binary packages
[B] MISSING "patchelf": required to relocate binaries
Spack will take care of bootstrapping any missing dependency marked as [B]. Dependencies marked as [-] are instead required to be found on the system.
其中标有 [B]
的项目是可以通过 spack 命令安装的。执行以下命令:
spack bootstrap now
在此过程中 Spack 将安装一些软件,需要访问 Spack 软件源,因此要保持网络畅通。安装完成后,再次用 spack bootstrap status
查询引导状态,应该得到以下输出:
Spack v0.22.2 - python@3.10
[PASS] Core Functionalities
[PASS] Binary packages
引导过程安装的软件独立于当前环境,在所有环境中有效。
注册编译器
虽然系统中已经安装了编译环境,但是 Spack 将编译器版本作为软件包规格的一部分,不同编译器版本编译得到的软件包被视为不同的实体,因此需要向 Spack 环境注册所用的编译器。
用以下命令检查是否有注册的编译器:
spack compiler list
如果输出为:
==> No compilers available. Run `spack compiler find` to autodetect compilers
表明没有编译器注册到 Spack. 按提示执行命令:
spack compiler find
输出信息:
==> Added 1 new compiler to /home/user/opt/spack-trunk/environments/default/spack.yaml
gcc@11.4.0
==> Compilers are defined in the following files:
/home/user/opt/spack-trunk/environments/default/spack.yaml
以上信息表示 Spack 发现并注册了一个编译器 gcc@11.4.0
. 还可以看到注册编译器的信息写入了 default 环境下的 spack.yaml
配置文件,因此只对 default 环境有效,如果切换环境需要重新注册。实际上也可以在不激活任何环境的情况下注册编译器,这样编译器的配置信息将写入 ~/.spack/
目录下并对所有环境生效。
注册编译器之后再次运行 spack compiler list
则得到以下输出:
==> Available compilers
-- gcc ubuntu22.04-x86_64 ---------------------------------------
gcc@11.4.0
使用 Spack 安装软件
Spack 安装软件包分为两步。第一步将要安装的软件包添加到当前环境的 spec 中:
spack add ninja miniconda3 lmod
输出信息:
==> Adding ninja to environment default
==> Adding miniconda3 to environment default
==> Adding lmod to environment default
用以下命令可以查看当前环境的 spec 以及安装的软件等:
spack find
示例输出如下:
==> In environment default
==> 3 root specs
- lmod - miniconda3 - ninja
==> 0 installed packages
可以看到当前在 default 环境中,spec 中已经有了 lmod, miniconda3, ninja 三个软件包,但没有安装。用以下命令启动安装:
spack install
安装时需要下载软件包,请保持网络畅通。Spack 的主仓库网址为 https://mirror.spack.io
, 有些软件包可能从其他网址(比如 GitHub)下载。
安装完成后再次用 spack find
查看,将得到类似以下的输出:
==> In environment default
==> 3 root specs
[+] lmod [+] miniconda3 [+] ninja
==> Installed packages
-- linux-ubuntu22.04-sapphirerapids / gcc@11.4.0 ----------------
bc@1.07.1 expat@2.6.2 libffi@3.4.6 lua-luafilesystem@1.8.0 perl@5.38.0 tar@1.34 zstd@1.5.6
berkeley-db@18.1.40 gcc-runtime@11.4.0 libiconv@1.17 lua-luaposix@36.1 pigz@2.8 tcl@8.6.12
bzip2@1.0.8 gdbm@1.23 libmd@1.0.4 miniconda3@24.3.0 pkgconf@2.2.0 texinfo@7.0.3
ca-certificates-mozilla@2023-05-30 gettext@0.22.5 libxcrypt@4.4.35 ncurses@6.5 python@3.11.7 unzip@6.0
curl@8.7.1 glibc@2.35 libxml2@2.10.3 nghttp2@1.57.0 re2c@2.2 util-linux-uuid@2.38.1
diffutils@3.10 gmake@4.4.1 lmod@8.7.24 ninja@1.11.1 readline@8.2 xz@5.4.6
ed@1.4 libbsd@0.12.1 lua@5.4.6 openssl@3.3.0 sqlite@3.43.2 zlib-ng@2.1.6
==> 43 installed packages
可以看到 spec 中的软件已经安装完毕, 所有依赖的软件包也一并装上了。
有些软件在整个安装过程结束后,由于有了更新的版本并且不被依赖,可以移除。用以下命令进行垃圾回收:
spack gc -y
回收后再用 spack find
查看安装的软件包,输出如下:
==> In environment default
==> 3 root specs
[+] lmod [+] miniconda3 [+] ninja
==> Installed packages
-- linux-ubuntu22.04-sapphirerapids / gcc@11.4.0 ----------------
curl@8.7.1 glibc@2.35 lua@5.4.6 lua-luaposix@36.1 ncurses@6.5 ninja@1.11.1 readline@8.2 unzip@6.0
gcc-runtime@11.4.0 lmod@8.7.24 lua-luafilesystem@1.8.0 miniconda3@24.3.0 nghttp2@1.57.0 openssl@3.3.0 tcl@8.6.12 zlib-ng@2.1.6
==> 16 installed packages
可以发现很多软件包被卸载了。
使用模块
在上一节中我们用 Spack 安装了 Lmod. Lmod 是基于 Lua 语言的模块系统,可以通过设置环境变量切换当前正在使用的软件和版本。Spack 可以生成 Lmod 需要的模块文件:
yes | spack module lmod refresh
示例输出如下:
==> You are about to regenerate lmod module files for:
-- linux-ubuntu22.04-sapphirerapids / gcc@11.4.0 ----------------
asaqxs2 curl@8.7.1 mbgwt3e lua@5.4.6 gvdbq6r ncurses@6.5 e5ystvq readline@8.2
crgekml gcc-runtime@11.4.0 a6aestx lua-luafilesystem@1.8.0 5p4ws6y nghttp2@1.57.0 dlnztsa tcl@8.6.12
ogqwpqt glibc@2.35 kaolr5l lua-luaposix@36.1 kbx3zt5 ninja@1.11.1 xwirqbp unzip@6.0
rojo73r lmod@8.7.24 6rcbqvg miniconda3@24.3.0 wxhohi6 openssl@3.3.0 vgkztpt zlib-ng@2.1.6
==> Do you want to proceed? [y/n] ==> Regenerating lmod module files
生成的模块文件放在 ~/opt/spack-trunk/modules
目录下。用以下命令加载模块文件:
module use ~/opt/spack-trunk/modules/linux-ubuntu22.04-x86_64/Core
这一命令已内置在登录脚本中,所以我们只需要退出并重新登录就可以了。
用以下命令可以列出当前可用的模块:
module avail
将输出类似下面的信息:
------------------------------------------ /home/user/opt/spack-trunk/modules/linux-ubuntu22.04-x86_64/Core ------------------------------------------
curl/8.7.1-asaqxs2 lua-luafilesystem/1.8.0-a6aestx ncurses/6.5-gvdbq6r readline/8.2-e5ystvq
gcc-runtime/11.4.0-crgekml lua-luaposix/36.1-kaolr5l nghttp2/1.57.0-5p4ws6y tcl/8.6.12-dlnztsa
glibc/2.35-ogqwpqt lua/5.4.6-mbgwt3e ninja/1.11.1-kbx3zt5 unzip/6.0-xwirqbp
lmod/8.7.24-rojo73r miniconda3/24.3.0-6rcbqvg openssl/3.3.0-wxhohi6 zlib-ng/2.1.6-vgkztpt
以下略 ......
用 module load
命令可以加载想使用的模块。以 curl 为例,首先查看当前生效的 curl 命令:
user@slurm-client:~$ type curl
curl is /home/user/opt/spack-trunk/environments/default/.spack-env/view/bin/curl
可以看到当前生效的 curl 命令路径。在上述的可用模块列表中我们发现有 curl, 用如下命令加载它:
module load curl
如果可用模块列表中有某个软件的多个版本,可以指明要加载的版本,比如:
module load curl/8.7.1
再次查看生效的 curl 路径:
user@slurm-client:~$ type curl
curl is /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/curl-8.7.1-asaqxs2tw2z7jv6kjea53ksnnlmbdlqh/bin/curl
可见生效的 curl 路径已切换。注意在本例中,加载前后的两个 curl 实际上是同一个文件,前者是指向后者的符号链接。
用以下命令可以查看当前加载的所有模块:
module list
示例输出如下:
Currently Loaded Modules:
1) glibc/2.35-ogqwpqt 3) nghttp2/1.57.0-5p4ws6y 5) openssl/3.3.0-wxhohi6
2) gcc-runtime/11.4.0-crgekml 4) zlib-ng/2.1.6-vgkztpt 6) curl/8.7.1-asaqxs2
除了 curl 外,其他模块都是因为依赖关系加载的。用以下命令卸载 curl 模块:
module unload curl
这时生效的 curl 又回到了原来 default 环境中的默认路径。
使用 miniconda 安装软件包
我们已经用 Spack 装好了 miniconda3 软件,现在可以用它来安装训练任务所需的 python 包。为了方便,先执行初始化:
conda init
示例输出如下:
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/condabin/conda
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/bin/conda
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/bin/conda-env
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/bin/activate
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/bin/deactivate
modified /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/etc/profile.d/conda.sh
modified /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/etc/fish/conf.d/conda.fish
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/shell/condabin/Conda.psm1
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/shell/condabin/conda-hook.ps1
no change /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/lib/python3.12/site-packages/xontrib/conda.xsh
modified /home/user/opt/spack-trunk/tree/linux-ubuntu22.04-sapphirerapids/gcc-11.4.0/miniconda3-24.3.0-6rcbqvgxlcgjyw5o5m73xax5ithtghqw/etc/profile.d/conda.csh
modified /home/user/.bashrc
==> For changes to take effect, close and re-open your current shell. <==
可见 conda 修改了用户的 .bashrc 配置文件以完成初始化,按提示退出并重新登录客户端,使修改过的配置生效。
现在开始使用 conda 安装软件包。首先激活默认的 base 环境(注意这个是 conda 环境,不是 Spack 环境):
conda activate base
激活之后提示符变为:
(base) user@slurm-client:~$
为本次训练任务安装以下软件包:
conda install -y -c pytorch -c nvidia pytorch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 pytorch-cuda=12.1
conda install -y -c conda-forge transformers scikit-learn deepspeed protobuf peft sentencepiece einops mpi4py
使用 pip 安装漏掉的包(这个包用 conda 安装的话,实际并没有装上所需的 python 模块):
pip install ninja