侧边栏壁纸
  • 累计撰写 218 篇文章
  • 累计创建 59 个标签
  • 累计收到 5 条评论

在集群上通过docker部署slurm集群

barwe
2024-02-01 / 1 评论 / 0 点赞 / 1,407 阅读 / 7,615 字
温馨提示:
本文最后更新于 2024-02-01,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

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
0

评论区