利用 Modules 动态管理集群中的基础软件环境

前言

  Modules 包是一款简化 shell 初始化的工具,允许用户在会话期间使用模块文件轻松切换环境。

------ Environment Modules 官网

  在高性能集群或者超算中,我们可以经常看到 Modules 的身影。它可以帮助我们轻松加载运行程序所需的各类环境,比如说笔者之前写过的第一性原理计算软件 CONQUEST 的运行,就需要包括 Intel OneAPI HPCKit、FFTW3、LibXC 在内的多种环境;又比如说运行大规模的机器学习模型时,可能需要 Python、GPU 环境和 PyTorch 等依赖库。

  由于集群往往是面向很多人服务的,如果管理员将软件安装到全局环境,则只能安装某个软件的某个特定版本,而不能同时为不同的用户提供所需的同款软件的不同版本。举个例子,笔者编写的代码只能在 Python 3.10 环境下运行,而其他用户编写的代码所支持的 Python 版本是 3.0,那么可能最简单的解决方法是笔者自行编译一个 Python 3.10 的环境,然后利用 PATH 等变量的配置来提升优先级。或许之后有一天,另外一个用户也要使用 Python 3.10 环境,那么是不是让他再自行编译配置一遍呢?哈哈哈,听起来有点无奈,但是千万不要高估集群的使用用户,可能自行编译并配置 Python 3.10 对他们来说也有点困难。因此,Modules 成为了集群动态管理软件环境的最佳选择。集群管理员可以预先编译和配置好各种环境的各种版本,用户使用时只需要执行类似 module load py/3.10.6 的命令就可以轻松加载 Python 3.10.6 环境。

  Modules 所支持的模块不仅仅可以是编程语言的多版本,还可以是其他任意的基础环境,比如说 gcc、openmpi 等编译环境。这样一来,不仅可以为用户提供足够的编程环境直接使用,还可以为一些想要自行编译运行环境的用户提供了便利。

实践

源码编译安装 Modules

  Modules 可以在 Linux、Windows、MacOS 任一操作系统上安装运行,这里仅介绍类 Unix 操作系统下的编译安装过程。由于 Modules 需要使用 tcl 工具来解析 modulefiles,所以系统必须预先安装 tcl 及其开发者库。

# 根据实际情况三者选其一
# Debian/Ubuntu 等 APT 系列操作系统上安装 tcl
sudo apt install -y tcl tcl-dev
# CentOS 等 YUM 系列操作系统上安装 tcl
sudo yum install -y tcl tcl-devel
# MacOS 操作系统上安装 tcl (需有 brew 工具)
brew install tcl-tk

# 下载源代码并解压
wget -c https://github.com/cea-hpc/modules/releases/download/v5.1.1/modules-5.1.1.tar.gz
tar xfz modules-5.1.1.tar.gz

# 创建安装目录
sudo mkdir -p /opt/modules

# 进入目录并配置安装目录
cd modules-5.1.1
./configure --prefix=/opt/modules
# MacOS 可能需要如下另外指定 tclConfig.sh 文件所在的位置
./configure --prefix=/opt/modules --with-tcl=/opt/homebrew/opt/tcl-tk/lib

# 编译并安装到 /opt/modules 目录
make && sudo make install

使 Modules 生效

  并非是编译完了之后就可以直接使用 Modules,还有至关重要的一步–添加生效命令。首先需要确认当前使用的 Shell 是什么,一般来说默认是 Bash,当然也有 Zsh 等等。然后,在对应的 Shell 配置文件中增加一行生效命令。操作如下所示:

# 确认当前使用的 Shell
╰─$ echo $SHELL
/bin/zsh

# 查看 Modules 支持的 Shell
╰─$ ls /opt/modules/init
bash            cmake           fish            ksh             lisp            profile.csh     python.py       ruby.rb         tcl             tcsh_completion zsh-functions
bash_completion csh             fish_completion ksh-functions   perl.pm         profile.sh      r.R             sh              tcsh            zsh
# 如上所示,大部分流行的 Shell 都在支持列表中

# 使 Modules 生效
vim ~/.zshrc
# 添加以下内容
source /opt/modules/init/zsh

源码编译安装 tcl

  Modules 的编译安装是不是很简单?不过如果 tcl 工具无法使用命令安装的话,就只能从源码编译安装,也比较方便,如下所示:

# 下载源码并解压
wget -c https://prdownloads.sourceforge.net/tcl/tcl8.6.12-src.tar.gz
tar xfz tcl8.6.12-src.tar.gz

# 创建安装目录
sudo mkdir /opt/tcl

# 进入目录并配置安装目录
cd tcl8.6.12/unix
./configure --prefix=/opt/tcl

# 编译并安装
make && sudo make install

Modules 相关命令

# 查看所有可用模块
module avail / module ava

# 加载指定模块(支持同时加载多个模块)
module load py/3.10.6 mpi

# 查看已加载模块
module list

# 查看指定模块
module show py/3.10.6

# 添加自定义模块配置目录
module use --apend ~/opt/modulefiles

添加软件环境

Modulefiles 库

  Modules 编译安装后默认会有一些环境,它们的配置文件都被存储在安装目录的 modulefiles 文件夹中,如下所示:

╰─$ module ava
--------------------------- /opt/modules/modulefiles ---------------------------
dot  module-git  module-info  modules  null  use.own

Key:
modulepath

╰─$ ls /opt/modules/modulefiles
dot         module-git  module-info modules     null        use.own

  一般来说,打算提供给所有用户的环境配置都可以放在这个目录里,这样任何用户都可以查看到。

Modulefiles 模板

  这里我们可以把 use.own 文件作为模板来学习一下如何编写 Modulefiles 文件。

#%Module1.0#####################################################################
##
## use.own modulefile
##
proc ModulesHelp { } {
    puts stderr "\tThis module file will add \$HOME/privatemodules to the"
    puts stderr "\tlist of directories that the module command will search"
    puts stderr "\tfor modules.  Place your own module files here."
    puts stderr "\tThis module, when loaded, will create this directory"
    puts stderr "\tif necessary."
}

module-whatis   "adds your own modulefiles directory to MODULEPATH"

eval set  [ array get env HOME ]
set ownmoddir   $HOME/privatemodules

# create directory if necessary
if [ module-info mode load ] {
    if { ! [ file exists $ownmoddir ] } {
        file mkdir $ownmoddir
        set null [open $ownmoddir/null w]
        puts $null "#%Module########################################################################"
        puts $null "##"
        puts $null "## null modulefile"
        puts $null "##"
        puts $null "proc ModulesHelp { } {"
        puts $null "    puts stderr \"\tThis module does absolutely nothing.\""
        puts $null "    puts stderr \"\tIt's meant simply as a place holder in your\""
        puts $null "    puts stderr \"\tdot file initialization.\""
        puts $null "}"
        puts $null ""
        puts $null "module-whatis   \"does absolutely nothing\""
    }
}

module use --append $ownmoddir

  Modulefiles 文件一般符合以下规则:

  • Modulefiles 文件必须以 #%Module1.0 开头;
  • 使用 proc ModulesHelp {} 函数来添加模块详细描述;
  • 使用 module-whatis 字段来添加一句话简短描述;
  • 使用 eval set [ array get env HOME] 来获取系统变量 $HOME
  • 使用 set ownmoddir 来定义变量 ownmoddir
  • 后续脚本可以根据需求进行添加内容。

  这里先开个坑,后续打算补充 Modules 配置系列文章:

参考资料

版权声明: 如无特别声明,本文版权归 仲儿的自留地 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 集群动态环境管理神器 Modules 》

本文链接:https://lisz.me/tech/webmaster/modules.html

本文最后一次更新为 天前,文章中的某些内容可能已过时!