使用Modulefile加载Conda环境

目录

本文介绍如何在 Environment Modules 管理软件的系统中实现使用 module 加载 conda 环境。

背景

笔者使用的一台 HPC 上安装了 conda 环境,并使用 module 进行管理。

conda 环境的 modulefile 类似下面的代码,设置了一些环境变量,并将 conda 所在的目录添加到环境变量 PATH 中。

setenv          CONDA_SHLVL 0
setenv          _CE_M {}
setenv          CONDA_EXE /g1/app/apps/anaconda_gpu/bin/conda
setenv          CONDA_PYTHON_EXE /g1/app/apps/anaconda_gpu/bin/python
setenv          _CE_CONDA {}
prepend-path    PATH /g1/app/apps/anaconda_gpu/condabin:/g1/app/apps/anaconda_gpu/bin

加载该模块后,可以使用 conda 命令,但无法直接激活 env 环境。 执行 conda activate base 命令后,会提示需要使用 conda init 初始化 shell 环境。

$conda activate base

CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'.
To initialize your shell, run

    $ conda init <SHELL_NAME>

Currently supported shells are:
  - bash
  - fish
  - tcsh
  - xonsh
  - zsh
  - powershell

See 'conda init --help' for more information and options.

IMPORTANT: You may need to close and restart your shell after running 'conda init'.

执行 conda init bash 后,会在 ~/.bashrc 中添加如下代码:

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/g1/app/apps/anaconda_gpu/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/g1/app/apps/anaconda_gpu/etc/profile.d/conda.sh" ]; then
        . "/g1/app/apps/anaconda_gpu/etc/profile.d/conda.sh"
    else
        export PATH="/g1/app/apps/anaconda_gpu/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

再次使用 conda activate base 就可以在命令行正常激活 env 环境。

如果只使用一个 conda 安装环境,该方法比较方便,HPC 中的多个账户也都采用上述方法来使用 conda 环境。

但如果想使用不同目录中的 conda 环境,尤其是 anaconda 和 miniforge 混用,上述方法可能会导致未配置到 .bashrc 中的 conda 环境失效。

下面介绍一种不修改 .bashrc 文件而直接使用 module 命令加载 conda 环境的方法。

方法

前期准备

在用户目录安装一个 minoforge3 环境,在安装过程中,选择不修改 .bashrc。 例如在如下目录中安装:

/g4/wangdp/lang/python/24.11/miniforge3

为该环境创建一个加载 conda 环境的脚本,例如创建 /g4/wangdp/lang/python/24.11/start_on_bash.sh 脚本,内容如下:

eval "$(/g4/wangdp/lang/python/24.11/miniforge3/bin/conda shell.bash hook)"

该脚本用于在 bash 中配置 conda 并激活 base 环境。 可以手动调用测试该脚本是否能在当前命令行终端中加载 conda:

. /g4/wangdp/lang/python/24.11/start_on_bash.sh

任意账户执行上述命令都可以加载用户安装的 python 环境,目前笔者也在业务账户的部分任务脚本中通过这种方式加载其他账户安装的 conda 环境。

不过,绝对路径不方便记忆,使用 modulefile 更容易管理软件包。

编写 modulefile

需要编写一个 modulefile 自动执行上述脚本。

modules 4.6 及以上版本提供 source-sh 命令用于执行 source 命令加载 shell 脚本。 但 HPC 的 modules 为 4.5 版本,可以使用 puts 命令实现。

编写一个 modulefile,路径 /g1/u/wangdp/modules/wangdp/share/lang/python/24.11,内容如下:

#%Module1.0
module-whatis   "Python env for 2024.11"

setenv MINIFORGE3_START_SCRIPT "/g4/wangdp/lang/python/24.11/start_on_bash.sh"

puts stdout {. ${MINIFORGE3_START_SCRIPT}}

puts stdout 相当于在当前 shell 环境中执行后续字符串表示的命令,{}用于阻止变量在 TCL 脚本内展开。

上述 modulefile 相当于在当前 shell 环境执行 . ${MINIFORGE3_START_SCRIPT} 命令,环境变量 MINIFORGE3_START_SCRIPT 是之前创建的 conda 加载脚本。

测试

在命令行和 slurm 队列中测试新建的 modulefile 是否有效。

命令行

首先需要将 modulefile 所在目录或其父目录添加到 MODULEPATH 环境变量中

export MODULEPATH=/g1/u/wangdp/modules:$MODULEPATH

使用 module 命令加载模块:

[wangdp@login_a11 /g1/u/wangdp]$module load wangdp/share/lang/python/24.11
(base) [wangdp@login_a11 /g1/u/wangdp]$conda activate py311
(py311) [wangdp@login_a11 /g1/u/wangdp]$which python
/g4/wangdp/lang/python/24.11/miniforge3/envs/py311/bin/python

可以看到 module load 加载后直接激活了 base 环境。

slurm 作业

在提交到 slurm 队列的脚本中测试 modulefile 是否有效。

为了方便,笔者使用 ecFlow 的 alias 功能进行测试,生成一个单独的脚本提交到 slurm 串行队列 serial 中,简化后的脚本如下所示:

#!/bin/bash
#SBATCH -J GRAPES
#SBATCH -p serial
#SBATCH -o alias1.1
#SBATCH -e alias1.1.err

export MODULEPATH=/g1/u/wangdp/modules:$MODULEPATH
module load wangdp/share/lang/python/24.11
which python

conda activate py311
which python

输出如下

/g4/wangdp/lang/python/24.11/miniforge3/bin/python
/g4/wangdp/lang/python/24.11/miniforge3/envs/py311/bin/python

可以看到,modulefile 在 slurm 中依然有效。

总结

本文介绍的方法可以在同一个账户中安装多个 conda/miniforge3 运行环境,通过 module 命令提供方便的加载方式。

笔者后续将尝试使用该方法创建用于共享其他账户使用的 python 环境。

参考

modules 文档 puts 命令说明