SLURM 容器化部署到集群上需要:
- munge: 身份验证和加密工具,负责集群内数据通讯
- 数据库: 例如 mysql,负责存储集群数据
- slurmdbd: SLURM 访问数据库的服务,负责与数据库交互
- slurmctld: SLURM 管理节点服务,管理集群
- slurmd: SLURM 计算节点服务,负责计算
安装依赖
为了方便,我们可以将 munge, slurmctld, slurmdbd, slurmd 整合到一个镜像里面:
RUN apt-get update \
&& apt-get install -y iputils-ping telnet nano mysql-client \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" | tee /etc/timezone \
&& apt-get install -y munge slurm-wlm slurmdbd \
&& cd /etc && ln -s slurm-llnl slurm
- Line 5 安装了可能需要用到的调试工具 ping, telnet, nano 以及测试数据库连接的 mysql 命令
- Line 6-7 设置时区,跳过安装 slurm 包时出现的交互式设置时区的步骤
- Line 8 安装软件
- munge 提供 munge 服务
- slurm-wlm 提供 slurmctld, slurmd 服务
- slurmdbd 提供 slurmdbd 服务
- Line 9 软连接,因为相关服务器启动时会去 /etc/slurm 或者 /etc/slurm-llnl 下面找配置文件,干脆合二为一
使用 slurmdbd & slurmctld & slurmd 还需要进行一些额外的准备工作:
RUN mkdir -p /var/spool/slurmctld \
/var/spool/slurmd \
/var/lib/slurmd \
/var/log/slurm \
&& touch /var/lib/slurmd/node_state \
/var/lib/slurmd/front_end_state \
/var/lib/slurmd/job_state \
/var/lib/slurmd/resv_state \
/var/lib/slurmd/trigger_state \
/var/lib/slurmd/assoc_mgr_state \
/var/lib/slurmd/assoc_usage \
/var/lib/slurmd/qos_usage \
/var/lib/slurmd/fed_mgr_state \
&& chown -R slurm:slurm /var/*/slurm*
COPY t2/slurmdbd.env /etc/default/slurmdbd
COPY t2/slurmctld.env /etc/default/slurmctld
COPY t2/slurmd.env /etc/default/slurmd
容器内通过 service 管理 slurmdbd & slurmctld & slurmd 服务:
service start slurmdbd
service start slurmctld
service start slurmd
这将在后台启动守护进程。
然而我们在容器中运行上述进程时,必须要将其放在前台运行,这样才能维持容器的运行状态,否则容器会在挂起守护进程后直接关闭退出。
所以我们需要修改它们各自的 /etc/default/~ 文件:
- slurmdbd: /etc/default/slurmdbd
SLURMDBD_OPTIONS="-Dvvv"
- slurmctld: /etc/default/slurmctld
SLURMCTLD_OPTIONS="-Dvvv"
- slurmd: /etc/default/slurmd
SLURMD_OPTIONS="-Dvvv"
加上 -D 参数即可在前台运行,三兄弟非常统一。
后续还需要在 slurmctld 容器中运行 tgrpc,这两个都可以作为保持容器运行的进程。
如果使用 tgrpc 阻塞容器退出,启动 slurmctld 时就不能加 -D 参数。
docker-entrypoint.sh
#!/bin/bash
set -e
if [ "$1" = "slurmdbd" ]; then
echo "[INFO] Starting the MUNGE Authentication service (munged) ..."
service munge start
{
. /etc/slurm/slurmdbd.conf
until echo "SELECT 1" | mysql -h $StorageHost -u$StorageUser -p$StoragePass -P$StoragePort 2>&1 >/dev/null; do
echo "[INFO] Waiting for database to become active before starting slurmdbd ..."
sleep 2
done
echo "[INFO] Database is now active!"
}
echo "[INFO] Starting the Slurm Database Daemon (slurmdbd) ..."
sed -i 's/SLURMDBD_OPTIONS=".*"/SLURMDBD_OPTIONS="-Dvvv"/g' /etc/default/slurmdbd
service slurmdbd start
elif [ "$1" = "slurmctld" ]; then
echo "[INFO] Starting the MUNGE Authentication service (munged) ..."
service munge start
until 2>/dev/null >/dev/tcp/slurmdbd/6819; do
echo "[INFO] Waiting for slurmdbd to become active before starting slurmctld ..."
sleep 2
done
echo "[INFO] slurmdbd is now active!"
echo "[INFO] Starting the Slurm Controller Daemon (slurmctld) ..."
sed -i 's/SLURMCTLD_OPTIONS=".*"/SLURMCTLD_OPTIONS="-Dvvv"/g' /etc/default/slurmctld
service slurmctld start
elif [ "$1" = "slurmctld-tgrpc" ]; then
echo "[INFO] Starting the MUNGE Authentication service (munged) ..."
service munge start
until 2>/dev/null >/dev/tcp/slurmdbd/6819; do
echo "[INFO] Waiting for slurmdbd to become active before starting slurmctld ..."
sleep 2
done
echo "-- slurmdbd is now active!"
echo "[INFO] Starting the Slurm Controller Daemon (slurmctld) ..."
sed -i 's/SLURMCTLD_OPTIONS=".*"/SLURMCTLD_OPTIONS="-vvv"/g' /etc/default/slurmctld
service slurmctld start
echo "[INFO] Starting the TGRPC Server (tgrpc)..."
conda run -n base python /app/tgrpc/manage.py runserver -m ${TGRPC_MODE:-prod} -p ${TGRPC_PORT:-60321}
elif [ "$1" = "tgprc" ]; then
echo "[INFO] Starting the TGRPC Server (tgrpc)..."
conda run -n base python /app/tgrpc/manage.py runserver -m ${TGRPC_MODE:-prod} -p ${TGRPC_PORT:-60321}
elif [ "$1" = "slurmd" ]; then
echo "[INFO] Starting the MUNGE Authentication service (munged) ..."
service munge start
echo "[INFO] Waiting for slurmctld to become active before starting slurmd..."
until 2>/dev/null >/dev/tcp/slurmctld/6817; do
echo "[INFO] slurmctld is not available. Sleeping ..."
sleep 2
done
echo "[INFO] slurmctld is now active!"
echo "[INFO] Starting the Slurm Node Daemon (slurmd) ..."
sed -i 's/SLURMD_OPTIONS=".*"/SLURMD_OPTIONS="-Dvvv"/g' /etc/default/slurmd
service slurmd start
else
exec "$@"
fi
docker-compose.yml
version: "3.8"
services:
slurmdb:
container_name: ${container_prefix}-slurmdb
image: mariadb:10.8.2
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: slurm_acct_db
MYSQL_USER: slurm
MYSQL_PASSWORD: "123456"
command: ["--port=3308"]
volumes:
- ./data/mysql:/var/lib/mysql
slurmdbd:
container_name: ${container_prefix}-slurmdbd
image: ${slurm_bonus_image}
command: ["slurmdbd"]
volumes:
- ./etc/slurmdbd.conf:/etc/slurm/slurmdbd.conf
depends_on:
- slurmdb
slurmctld:
container_name: ${container_prefix}-slurmctld
image: ${slurm_bonus_image}
command: ["slurmctld-tgrpc"]
volumes:
- ./etc/slurm.conf:/etc/slurm/slurm.conf
- ./env.toml:/app/tgrpc/env.toml
- /home/barwe/projects/MS/tgrpc:/app/tgrpc
- ./data/graphs:/root/.cache/tgrpc/graphs
ports:
- 60444:60321
depends_on:
- slurmdbd
manage01:
hostname: manage01
container_name: ${container_prefix}-manage01
image: ${slurm_bonus_image}
command: ["slurmd"]
volumes:
- ./etc/slurm.conf:/etc/slurm/slurm.conf
slurmd.service 解读
$ cat /usr/lib/systemd/system/slurmd.service
[Unit] # 包含有关服务单元的元数据,例如服务的描述、依赖关系和启动顺序
Description=Slurm node daemon
# 定义服务启动的顺序和依赖关系,它指定了在启动当前服务之前需要启动的其他服务
# 确保在服务启动时按照指定的顺序启动其他服务
# 这对于有依赖关系的服务非常有用,以确保它们按正确的顺序启动。
# After 指令只定义了启动顺序,并不表示依赖关系。如果你想要明确的依赖关系,请使用 Requires 或 Wants 指令
# network.target 表示在网络可用时启动服务
# remote-fs.target 表示在远程文件系统可用时启动服务
# "在远程文件系统可用时" 意味着系统已经成功地挂载了远程文件系统,并且可以访问该文件系统中的文件和目录
After=munge.service network.target remote-fs.target
# Optional 检查指定的路径是否存在。它可以用于在启动服务之前进行条件检查
# 如果路径不存在,则条件不满足,服务将不会被启动
ConditionPathExists=/etc/slurm-llnl/slurm.conf
# Optional 提供关于服务的文档信息和参考资料
# 指向服务文档的链接地址。你可以提供一个或多个链接,用空格或逗号分隔它们
Documentation=man:slurmd(8)
[Service] # 包含有关服务的执行方式和运行环境的信息。你可以设置服务的启动命令、工作目录、环境变量等。
# 定义服务的类型:简单服务(simple)、守护进程服务(forking)、或者其他类型
# simple: 服务是一个简单的命令行程序,当该程序启动后,systemd 认为服务已经启动完成
# forking: 服务是一个以守护进程方式运行的程序,当该程序启动后,systemd 会等待它创建一个子进程,并认为服务已经启动完成
# oneshot: 服务是一个执行一次性任务的程序,当该程序启动后,systemd 认为服务已经完成,并立即退出
# dbus: 服务是一个 D-Bus 服务
# notify: 服务会通过发送通知来告知 systemd 服务已经启动完成
# 选择适合的 Type 类型,确保 systemd 对服务的运行和管理方式进行正确的处理
Type=forking
# 指定一个文件,该文件包含了服务运行时所需的环境变量
# 按行列出环境变量的键值对,例如 KEY1=value1
# 将环境变量的配置从 .service 文件中分离出来,并将其存储在单独的文件中
# 可以更方便地管理和更新环境变量,而不必修改 .service 文件
EnvironmentFile=-/etc/default/slurmd
# 定义服务启动时要执行的命令或程序
# 如果你需要执行多个命令或程序,可以使用分号或换行符将它们分隔开
ExecStart=/usr/sbin/slurmd $SLURMD_OPTIONS
# 定义服务重新加载时要执行的命令或程序
# `$MAINPID` 是一个特殊的变量,在 systemd 启动服务时,它会被替换为实际的主进程 ID
# 确保你的服务支持通过发送 `SIGHUP` 信号来重新加载配置或状态
ExecReload=/bin/kill -HUP $MAINPID
# 在 `.service` 文件中,`PIDFile` 指令用于指定一个文件,该文件用于存储服务的进程 ID
PIDFile=/run/slurmd.pid
# 定义当服务被停止或重载时,如何发送信号以终止服务的进程
# - `control-group`:默认值。当服务被停止或重载时,systemd 将会向服务所在的控制组(cgroup)发送信号,以终止服务的进程。
# - `process`:当服务被停止或重载时,systemd 将会向服务的主进程发送信号,以终止服务的进程。
# - `mixed`:当服务被停止时,systemd 将会向服务所在的控制组发送信号,以终止服务的进程。当服务被重载时,systemd 将会向服务的主进程发送信号,以触发重新加载。
KillMode=process
# 限制服务进程可以打开的文件描述符(file descriptor)的数量
# 通过限制文件描述符的数量,可以对服务进程的资源使用进行控制,防止过多的文件描述符占用系统资源
LimitNOFILE=131072
# 限制服务进程可以锁定在内存中的最大字节数
# 通过限制内存锁定的大小,可以控制服务进程在内存中锁定的资源量,以防止过度使用系统内存资源
LimitMEMLOCK=infinity
# 限制服务进程可以使用的堆栈(stack)的最大大小
# 通过限制堆栈的大小,可以控制服务进程在内存中分配给堆栈的资源量,以防止过度使用系统内存资源
LimitSTACK=infinity
# 指定是否允许服务进程创建子进程,默认值为 `yes`
Delegate=yes
# 限制服务进程可以创建的最大任务数(即进程数)
# 通过限制任务数,可以控制服务进程的并发执行数量,防止过多的任务占用系统资源
TasksMax=infinity
[Install] # 指定服务的启动级别和依赖关系
# 服务单元所依赖的目标
# 通过设置 `WantedBy` 指令,可以指定服务单元在何时启动或停止。当指定的目标被触发时,相关的服务单元将被启动或停止。
# `multi-user.target` 是一个常见的目标,表示在多用户模式下启动服务
# `WantedBy` 指令的值应该是一个有效的目标名称,它可以是其他服务单元或特定的系统目标
WantedBy=multi-user.target
评论区