Spack离线部署
一、离线部署
1. release下载(推荐)
github下载最新的release:https://github.com/spack/spack/releases
2.激活
对于超算/lab/hpc等多用户场景,建议将spack本地放在
全局/共享目录下单个普通用户建议放在
~/.spack/或/opt下
解压下载好的压缩包, 加载环境变量(根据具体情况变更路径):
source spack/share/spack/setup-env.sh
可以将此命令写在~/.bashrc 或 /etc/profile 中 , 打开终端自动生效
3.添加编译器
运行下面命令可找到当前系统环境下的编译器
spack compiler find
4.配置离线 clingo-bootstrap
如果没配置,spec某个软件会报这样的错误

原因是spack 依靠 clingo-bootstrap 这个python库实现解析软件的一些功能
我们在一台联网机器上,使用相同版本的spack 创建一个离线的clingo-bootstrap的源码仓库
spack bootstrap mirror --binary-packages ~/mirror
创建好后,压缩,上传到目标服务器,解压,配置bootstrap.yaml,运行下面的命令
spack bootstrap add --trust local-sources mirror所在的目录/metadata/sources
spack bootstrap add --trust local-binaries mirror所在的目录/metadata/binaries
然后再次 spack spec zlib

这次会自动编译相关依赖库,最后编译好clingo-bootstrap ,spack spec就正常输出了,而clingo-bootstrap和它的依赖安装目录是在 ~/.spack/bootstrap下
如果使用上面的方法依然报错,也可以用本地python
pip install clingo
二、离线编译和管理已编译好的软件
1.spack 基础配置
进入~/.spack,先运行下面的命令
spack config get config > config.yaml
修改该文件,
install_tree 下单root值为软件安装目录,可自行修改,
projections的all值为目录层级,我这里删去了架构层级
verify_ssl和checksum都可以关闭 这样能大幅提高安装速度
下面是我的配置文件
config:
  install_tree:
    root: $spack/app
    projections:
      all: '{compiler.name}-{compiler.version}/{name}-{version}-{hash}'
  template_dirs:
  - $spack/share/spack/templates
  license_dir: $spack/etc/spack/licenses
  build_stage:
  - $tempdir/$user/spack-stage
  - $user_cache_path/stage
  test_stage: $user_cache_path/test
  source_cache: $spack/var/spack/cache
  misc_cache: $user_cache_path/cache
  connect_timeout: 10
  verify_ssl: false
  ssl_certs: $SSL_CERT_FILE
  suppress_gpg_warnings: false
  install_missing_compilers: false
  checksum: false
  deprecated: false
  dirty: false
  build_language: C
  locks: true
  url_fetch_method: urllib
  ccache: false
  concretizer: clingo
  db_lock_timeout: 60
  package_lock_timeout: null
  shared_linking:
    type: rpath
  allow_sgid: true
  install_status: true
  binary_index_ttl: 600
  flags:
  aliases:
    concretise: concretize
    containerise: containerize
    rm: remove
  debug: false
  build_jobs: 16
2.搭建离线源码仓库
在一台有外网环境的机器上,使用下面的命令搭建
mkdir mirror
spack mirror create -d ~/mirror -a
将mirror打成tar包,上传到目标机器并解压
spack mirror add local mirror文件夹绝对路径

3.管理已编译好的软件
3.1 参考2. 我们创建一个私有的”源码“仓库
mkdir private_mirror
spack mirror add private private_mirror
3.2 创建私有的repo源
spack repo create private_repo
spack repo add /yeesuanAI01/spack/private_repo

3.4 管理已编译软件的基本流程
假设我们有个hello 软件,已经在本地编译好,目录结构如下

spack软件包名规则,无论是mirror下的源码还是repo下的包名,都需要遵循全部小写的规则,名字中有中划线的改下划线
我们将其打成tar包或者tgz包,并在私有源码仓库创建同名软件名单目录hello,将压缩包放入其中
mkdir /yeesuanAI01/spack/private_mirror/hello
mv hello.tgz /yeesuanAI01/spack/private_mirror/hello/hello_1.0.tgz
创建hello的自动安装脚本 这里大N是指定私有repo源的namespace 小n是这个软件的名字
spack create -N private_repo -n hello /yeesuanAI01/spack/private_mirror/hello/hello_1.0.tgz

我们将其改造一下,
from spack.package import *
class Hello(Package):
    """FIXME: Put a proper description of your package here."""
    homepage = "https://www.example.com"
    url = "/yeesuanAI01/spack/private_mirror/hello/hello_1.0.tgz"
    version("1.0", url="file:///yeesuanAI01/spack/private_mirror/hello/hello_1.0.tgz")
    def install(self, spec, prefix):
        install_tree(".", prefix)
其中最关键的就是install这个函数,这个脚本只执行安装操作,install_tree的作用就是讲源码包解压后的所有文件和文件夹拷贝到spack软件安装目录,其中prefix是解压后的文件夹的根目录,所以这里用了 “.” 代表所有文件和文件夹
每个version里的url 要指明要安装的软件的源码仓库的绝对路径
此时我们再次info下,就有了我们的hello软件

我们执行安装操作
spack install [email protected] %[email protected]

我们load下测试下

可以正常运行其bin目录下我们写好的echo hello脚本
3.4 脚本参考
这里是cp2k的脚本,用到了setup_run_environment 这个环境变量,我们可以在python脚本自定义各种环境变量,并添加多个“源码包”的版本号和其sha256值(sha256可以忽略不写)
from spack import *
class Cp2k(Package):
    """FIXME: Put a proper description of your package here."""
    homepage = "https://www.example.com"
    url = "file:///sh3/ysuanbase/home/yeesuan10000/mirror/yeesuan/cp2k/cp2k-2022.1.tgz"
    maintainers = ["libaolin"]
    version(
        "2022.1",
        sha256="c0bf3e12eb62e8923cf4b125fefc4fb6967d117463987cdc0056962d73ab4f71",
    )
    version(
        "9.1", sha256="bf2f9ad82ecc61f5a678057952a8ae6a8a6ab59e7749deb92adabf53994b1f18"
    )
    version("7.1")
    version(
        "8.2", sha256="c53c183c8771303c59eb8c4f47b9478242113f7a0590a051b36ffca127af3efd"
    )
    depends_on("intel-oneapi-mpi", type=("run"))
    def setup_run_environment(self, env):
        env.prepend_path(
            "LD_LIBRARY_PATH",
            "/sh3/ysuanbase/share/software/public/intel-oneapi-mkl-2021.4.0-tyzzcpsexzuimyioanwactzip7mwxlqf/mkl/2021.4.0/lib/intel64:/sh3/ysuanbase/share/software/public/intel-oneapi-mkl-2021.4.0-tyzzcpsexzuimyioanwactzip7mwxlqf/lib:/sh3/ysuanbase/share/software/public/gcc-11.1.0-bpl5646k57uu5yyfv7ss74w53m77pptt/lib64",
        )
        env.prepend_path(
            "LD_LIBRARY_PATH",
            "/sh3/ysuanbase/share/software/public/intel-oneapi-compilers-2021.4.0-45kefy3jlp46zmllxkd7ftrsdfrtgfwb/compiler/2021.4.0/linux/compiler/lib/intel64_lin",
        )
        env.prepend_path("LD_LIBRARY_PATH", self.prefix + "/env-lib")
        env.set("CP2K_DATA_DIR", self.prefix + "/data")
    def install(self, spec, prefix):
        install_tree(".", prefix)