본문으로 건너뛰기

[HPC From Scratch] 에피소드 5: Rocky Linux에서 Slurm 소스 컴파일 설치하기

Will Paik
작성자
Will Paik
대규모 GPU 클러스터를 최적화하는 HPC 엔지니어. 밤에는 방구석 미니 슈퍼컴퓨터를 조립하며(가끔은 태워 먹으며) 그 과정을 기록합니다.
HPC From Scratch - 이 글은 시리즈의 일부입니다.
파트 5: 이 글

스토리지와 인증 시스템이 갖춰졌습니다. 이제 클러스터에 두뇌를 달아줄 차례입니다.

에피소드 4에서는 NFS 공유 스토리지, FreeIPA 중앙 집중식 인증, Ansible 클러스터 관리를 설정했습니다. 모든 노드가 동일한 홈 디렉토리를 공유하고 사용자 계정이 어디서든 작동합니다.

하지만 지금 상태에서 작업을 실행하려면 컴퓨트 노드에 직접 SSH 접속해서 바로 실행해야 합니다. 한 명이 한 노드에서 쓸 때는 괜찮습니다. 두 사람이 같은 노드를 동시에 쓰거나, 여러 노드에 걸쳐 작업을 조율해야 할 때는 무너져요. 그게 작업 스케줄러가 해결하는 문제입니다.

이번 에피소드에서는 Slurm을 다룹니다. 소스에서 빌드하는 이유, Munge가 노드 간 인증을 처리하는 방식, slurm.conf가 실제로 제어하는 것들, 그리고 첫 번째 실제 클러스터 작업 제출까지요.

1. Slurm이 실제로 하는 일
#

작업 스케줄러 없는 공유 클러스터는 조율이 없는 주방과 같습니다. 모두가 원할 때 리소스를 가져갑니다. 한 사람의 작업이 다른 사람을 굶겨요. 두 노드를 동시에 요청하면서 동시에 둘 다 사용 가능하다는 보장을 받을 방법이 없습니다.

Slurm은 HPC 101 시리즈에서 말한 프런트 데스크 직원입니다. 확장된 버전으로요. 모든 노드의 모든 CPU, 모든 기가바이트의 메모리, 모든 GPU를 추적합니다. 작업을 제출하면 Slurm이 요청한 리소스가 사용 가능할 때까지 큐에 넣고, 적절한 노드에 배정해서 실행합니다.

필요한 세 가지 컴포넌트입니다.

slurmctld는 관리 노드(arbiter)에서 실행됩니다. 컨트롤러입니다. 큐를 유지하고, 스케줄링 결정을 내리고, 컴퓨트 노드와 통신합니다.

slurmd는 각 컴퓨트 노드에서 실행됩니다. 컨트롤러로부터 작업 배정을 받고, 실제 작업을 실행하고, 결과를 보고합니다.

slurmdbdarbiter에서 실행됩니다. Slurm을 MariaDB 데이터베이스에 연결하고 모든 작업을 기록합니다. 누가 실행했는지, 얼마나 걸렸는지, CPU와 메모리를 얼마나 썼는지요. 이게 seff, sacct, 그리고 페어 쉐어(Fair Share) 스케줄링을 가능하게 합니다.

Slurm 아키텍쳐 다이어그램

2. 소스에서 빌드하는 이유
#

당연한 질문은 왜 dnf install slurm을 안 쓰냐는 겁니다. 두 가지 이유가 있습니다.

버전 제어. 모든 노드에서 dnf upgrade를 실행하면 Slurm도 업그레이드됩니다. slurmctld와 slurmd 간 버전 불일치는 클러스터를 망가뜨려요. 컨트롤러와 컴퓨트 노드는 동일한 버전을 실행해야 합니다. 소스에서 빌드하고 RPM으로 배포하면 Slurm 업데이트 시점을 시스템의 나머지와 분리해서 직접 제어할 수 있습니다.

기능 지원. Rocky Linux 10은 기본적으로 cgroup v2를 사용합니다. 오래된 Slurm 빌드는 cgroup v1을 기본으로 해서 작업 어카운팅과 메모리 추적이 소리 없이 실패합니다. 소스에서 빌드하면 --with cgroupv2를 명시적으로 전달할 수 있습니다. 마찬가지로 MPI 작업 실행을 위한 PMIx 지원도 표준 배포 패키지에 포함되지 않은 빌드 플래그가 필요합니다.

빌드 프로세스는 관리 노드(arbiter)에서 Slurm을 컴파일하고 RPM으로 패키징한 다음 Ansible로 모든 노드에 배포합니다.

# arbiter에서 빌드, Slurm 25.11.1 대상
rpmbuild -ta slurm-25.11.1.tar.bz2 \
  --define "_slurm_sysconfdir /etc/slurm" \
  --with cgroupv2 \
  --with pmix

런타임 의존성을 위한 EPEL
#

빌드가 gtk2-devel을 개발 의존성으로 가져오면서 결과 slurm 기본 RPM이 GTK2 런타임 라이브러리(libgdk-x11-2.0.so.0, libgtk-x11-2.0.so.0)에 의존하게 됩니다. Rocky Linux 10의 기본 저장소에는 이 라이브러리가 없습니다. EPEL에 있거든요. 섹션 4의 설치 전에 모든 노드에서 EPEL이 활성화되어야 합니다. 안 그러면 dnf가 depsolve 오류로 로컬 RPM을 거부합니다.

[wpaik@arbiter ansible]$ ansible all_nodes -b -m dnf -a "name=epel-release state=present"

GTK2 의존성을 완전히 피하고 싶다면 rpmbuild--without gtk를 전달하면 sview가 빌드에서 제외됩니다. HPC 컴퓨트 노드에서는 어차피 sview를 실행하지 않으니 헤드리스 클러스터에서는 더 깔끔한 옵션입니다.

모든 빌드 의존성, 전체 빌드 플레이북, RPM 배포 플레이북은 GitHub 저장소에 있습니다.

3. Munge: 인증 레이어
#

Slurm이 노드 간 통신을 하려면 메시지가 클러스터에서 실제로 오는 것인지 다른 곳이 아닌지 확인할 방법이 필요합니다. 그게 Munge의 역할입니다.

Munge는 공유 비밀 키를 사용해서 암호화된 토큰을 생성합니다. 클러스터의 모든 노드가 /etc/munge/munge.key에 동일한 키를 가지고 있습니다. slurmctld가 slurmd에 메시지를 보낼 때 Munge 토큰을 첨부합니다. 컴퓨트 노드가 공유 키로 복호화하고 메시지가 합법적인지 확인합니다.

키는 arbiter에서 한 번 생성되고 Ansible로 모든 노드에 배포됩니다.

# arbiter에서 키 생성
dd if=/dev/urandom bs=1 count=1024 > /etc/munge/munge.key
chmod 400 /etc/munge/munge.key
chown munge:munge /etc/munge/munge.key

중요: Slurm UID는 모든 노드에서 일치해야 합니다.

Munge는 키뿐만 아니라 토큰을 생성한 프로세스의 UID도 검증합니다. slurm 사용자가 arbiter에서 UID 386이고 interceptor-01에서 UID 990이면, Munge가 보안 위반 오류로 토큰을 거부합니다. 클러스터가 시작되는 것처럼 보이지만 작업이 절대 실행되지 않습니다.

Slurm 설치 전에 모든 노드에서 Slurm 사용자의 UID를 1111로 고정합니다.

groupadd -g 1111 slurm
useradd -u 1111 -g slurm -s /bin/bash -d /var/lib/slurm slurm

모든 노드의 UID가 일치하는지 확인합니다.

[wpaik@arbiter ansible]$ ansible all_nodes -m shell -a "id slurm" -b
arbiter.cluster.local | rc=0 >>
uid=1111(slurm) gid=1111(slurm) groups=1111(slurm)
interceptor-01.cluster.local | rc=0 >>
uid=1111(slurm) gid=1111(slurm) groups=1111(slurm)
interceptor-02.cluster.local | rc=0 >>
uid=1111(slurm) gid=1111(slurm) groups=1111(slurm)
corsair-01.cluster.local | rc=0 >>
uid=1111(slurm) gid=1111(slurm) groups=1111(slurm)
carrier.cluster.local | rc=0 >>
uid=1111(slurm) gid=1111(slurm) groups=1111(slurm)

모두 일치합니다. Munge가 실행 중이고 공유 키가 작동하는지 확인합니다.

# 로컬에서 Munge 인증 테스트
$ munge -n | unmunge

# 노드 간 테스트
$ munge -n | ssh interceptor-01.cluster.local unmunge
STATUS:          Success (0)
ENCODE_HOST:     arbiter.cluster.local (192.168.50.50)
DECODE_HOST:     interceptor-01.cluster.local (192.168.50.15)
MUNGE_UID:       slurm (1111)

방화벽 참고: 워커 노드는 firewalld가 비활성화되어 있습니다. 로그인 노드(carrier)는 내부 인터페이스가 trusted 존에 있습니다. 컴퓨트 노드에서 firewalld를 실행 중이라면 포트 6817(slurmctld), 6818(slurmd), 6819(slurmdbd)를 엽니다.

4. Slurm 설치
#

arbiter에서 RPM을 빌드한 후 Ansible이 클러스터 전체에 배포하고 설치합니다. 각 노드는 역할에 따라 다른 패키지 세트를 받습니다.

노드 유형 패키지
관리 노드 (arbiter) slurm, slurmctld, slurmdbd, mariadb
컴퓨트 노드 (interceptor, corsair) slurm, slurmd, slurm-libpmi
로그인 노드 (carrier) slurm, slurm-contribs (seff 포함)

컴퓨트 노드의 slurm-libpmi는 MPI 구현체가 srun으로 병렬 프로세스를 실행할 때 사용하는 PMI2와 PMIx 라이브러리를 제공합니다. 없으면 MPI 작업이 srun을 런처로 쓸 때 PMI 버전 오류로 실패합니다.

로그인 노드의 slurm-contribs에는 작업 효율성 도구인 seff가 포함됩니다. slurmdbd의 어카운팅 데이터를 읽어서 작업이 요청한 것 대비 실제로 CPU와 메모리를 얼마나 썼는지 정확하게 보여줍니다.

설치 플레이북이 전제하는 두 가지 조건이 있습니다. 모든 노드에서 EPEL이 활성화되어 있어야 하고 (섹션 2), Ansible 컨트롤러의 remote_tmp가 대상 노드의 로컬 경로를 가리켜야 합니다 (에피소드 4의 ansible.cfg 설정). 두 번째가 중요한 이유는, 설치가 Ansible의 임시 디렉토리를 통해 RPM을 복사하기 때문입니다. 그 디렉토리가 NFS 위에 있으면 (이 클러스터에서는 /home이 NFS 마운트되어 있어서 기본값이 NFS 위입니다) RPM이 nfs_t SELinux 컨텍스트를 상속받아서, 파일이 디스크에 분명히 있는데도 dnf가 No match for argument 오류로 거부합니다. ansible.cfgremote_tmp = /var/tmp/.ansible-${USER}/tmp 줄이 임시 영역을 로컬 디스크에 두어 이 함정을 피합니다.

설치가 성공적으로 완료된 후 dnf에서 Slurm 버전을 고정해서 dnf upgrade가 다른 빌드를 가져오지 못하도록 합니다. 설치 플레이북의 마지막 단계가 이걸 처리합니다.

ansible all_nodes -b -m shell -a "echo 'exclude=slurm*' >> /etc/dnf/dnf.conf"

# 확인
ansible all_nodes -b -m shell -a "grep slurm /etc/dnf/dnf.conf"

순서가 중요합니다. 설치 성공 후에 고정하고, 절대 그 전에 하면 안 됩니다. 설치 전에 고정하면 dnf가 slurm 설치 자체를 거부합니다. 이것도 No match for argument 오류로요. Slurm을 업그레이드해야 할 때는 먼저 그 줄을 제거하고, 재빌드, 재설치한 다음 플레이북이 마지막에 고정을 다시 추가합니다.

전체 설치 플레이북은 GitHub 저장소의 ep05-slurm/playbooks/에 있습니다.

5. Slurm 설정
#

모든 Slurm 설정은 모든 노드의 /etc/slurm/slurm.conf에 있습니다. 파일은 클러스터 전체에서 동일해야 합니다. arbiter에서 생성하고 Ansible로 배포합니다.

이 클러스터의 전체 slurm.conf입니다.

# 클러스터 아이덴티티
ClusterName=cluster
SlurmctldHost=arbiter
SlurmUser=slurm
AuthType=auth/munge

# 스케줄링
SchedulerType=sched/backfill
SelectType=select/cons_tres
SelectTypeParameters=CR_Core_Memory

# 로깅
SlurmctldDebug=info
SlurmctldLogFile=/var/log/slurm/slurmctld.log
SlurmdDebug=debug
SlurmdLogFile=/var/log/slurm/slurmd.log

# 상태 및 PID 파일
StateSaveLocation=/var/spool/slurmctld
SlurmdSpoolDir=/var/spool/slurmd
SlurmctldPidFile=/run/slurm/slurmctld.pid
SlurmdPidFile=/run/slurm/slurmd.pid

# Cgroup (v2)
ProctrackType=proctrack/cgroup
TaskPlugin=task/cgroup,task/affinity

# 작업 어카운팅
JobAcctGatherType=jobacct_gather/cgroup
JobAcctGatherFrequency=30
AccountingStorageType=accounting_storage/slurmdbd
AccountingStorageHost=arbiter.cluster.local
AccountingStoragePort=6819
JobCompType=jobcomp/none
AccountingStorageTRES=gres/gpu
AccountingStoreFlags=job_comment,job_env,job_script

# GPU 지원
ReturnToService=1
GresTypes=gpu

# MPI 기본값
MpiDefault=pmix

# 노드
NodeName=interceptor-01 CPUs=8 Sockets=1 CoresPerSocket=4 ThreadsPerCore=2 RealMemory=15413 State=UNKNOWN
NodeName=interceptor-02 CPUs=8 Sockets=1 CoresPerSocket=4 ThreadsPerCore=2 RealMemory=15413 State=UNKNOWN
NodeName=corsair-01 CPUs=16 Sockets=1 CoresPerSocket=8 ThreadsPerCore=2 RealMemory=30802 Gres=gpu:nvidia_geforce_gtx_1660_super:1 State=UNKNOWN

# 파티션
PartitionName=cpu Nodes=interceptor-01,interceptor-02 Default=YES MaxTime=INFINITE State=UP
PartitionName=gpu Nodes=corsair-01 Default=NO MaxTime=INFINITE State=UP

몇 가지 짚어볼 점입니다.

RealMemory 값은 에피소드 2의 iGPU 메모리 함정에서와 마찬가지로 각 노드에서 free -m을 실행해서 구합니다. 여기 있는 값들은 하드웨어 예약 후 OS가 실제로 보고하는 값을 반영합니다. 설치된 RAM 숫자를 쓰면 안 됩니다.

MpiDefault=pmixsrun의 기본 MPI 프로세스 관리 인터페이스를 PMIx로 설정합니다. 없으면 srun이 기본적으로 PMI2를 쓰는데, 병렬 작업 실행 시 OpenMPI와 호환성 오류가 생겨요. MPI 작업이 멈추거나 PMI 버전 오류로 실패하면 여기를 먼저 확인합니다.

SelectTypeParameters=CR_Core_Memory는 리소스 할당 시 코어와 메모리를 모두 추적하라고 Slurm에 알려줍니다. seff가 메모리 사용량을 정확하게 보고하려면 필요합니다.

cgroup 설정은 별도 파일에 있습니다.

# /etc/slurm/cgroup.conf
ConstrainCores=yes
ConstrainRAMSpace=yes
ConstrainSwapSpace=no
ConstrainDevices=yes

ConstrainCoresConstrainRAMSpace는 작업 스크립트에서 요청한 리소스 한도를 강제합니다. 작업이 요청한 것보다 많은 메모리를 쓰려 하면 Slurm이 조용히 소비하게 두는 대신 메모리 부족 오류로 종료합니다. cgroup v2가 필요한데, 이 클러스터에서 확인합니다.

$ stat -fc %T /sys/fs/cgroup
cgroup2fs

MariaDB와 slurmdbd는 어카운팅 데이터를 저장합니다. slurm_acct_db 데이터베이스와 slurm 데이터베이스 사용자를 만들고, slurmdbd가 연결하도록 설정합니다. /etc/slurm/slurmdbd.conf는 모드 600이고 slurm 사용자 소유여야 합니다. 안 그러면 slurmdbd가 시작을 거부합니다.

6. 컴퓨트 노드에서 스왑 비활성화
#

Slurm 작업 실행 전에 컴퓨트 노드에서 스왑을 비활성화해야 합니다. cgroup.confConstrainRAMSpace=yes가 설정되면 Slurm이 cgroup으로 메모리 한도를 강제합니다. 스왑이 활성화되면 RAM 한도에 걸린 프로세스가 종료되는 대신 스왑으로 넘어갈 수 있어서 메모리 제약이 무력화되고 seff 메모리 보고가 부정확해져요.

로그인 노드(carrier)와 관리 노드(arbiter)는 컴퓨트 작업을 실행하지 않으므로 스왑을 유지해도 됩니다.

systemd를 통해 컴퓨트 노드에서 영구적으로 스왑 비활성화:

ansible workers,gpu -b -m systemd \
  -a "name=swap.target state=stopped enabled=no"

다음 재부팅 후 확인:

$ cat /proc/swaps
Filename    Type    Size    Used    Priority
# 출력이 없으면 스왑이 꺼진 상태입니다

참고: 스왑 UUID가 /etc/fstab에 여전히 있을 수 있습니다. systemd에서 swap.target이 비활성화되어 있으면 괜찮습니다. 부팅 시 dependency 오류로 유닛이 활성화에 실패하는데, 이게 예상된 동작입니다.

7. 클러스터 시작
#

서비스는 순서대로 시작해야 합니다. slurmctld가 연결을 시도하기 전에 slurmdbd가 실행 중이어야 합니다.

# arbiter에서
$ sudo systemctl start mariadb
$ sudo systemctl start slurmdbd
$ sudo systemctl start slurmctld

# 각 컴퓨트 노드에서
$ sudo systemctl start slurmd

서비스가 시작되면 어카운팅 데이터베이스를 초기화합니다.

$ sacctmgr -i add cluster cluster
$ sacctmgr -i add account root Description="Root" Organization="Cluster"
$ sacctmgr -i add user wpaik Account=root

클러스터 상태 확인:

[wpaik@carrier ~]$ sinfo
PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
cpu*         up   infinite      2   idle interceptor-[01-02]
gpu          up   infinite      1   idle corsair-01

모든 노드가 idle 상태로 준비됐습니다. 노드가 idle 대신 down이나 drain으로 나오면 재시작합니다.

$ scontrol update NodeName=ALL State=RESUME

8. 첫 번째 작업 제출
#

인터랙티브 작업
#

[wpaik@carrier ~]$ srun --pty bash
[wpaik@interceptor-01 ~]$ hostname
interceptor-01
[wpaik@interceptor-01 ~]$ exit

srun이 기본 cpu 파티션의 첫 번째 노드인 interceptor-01에 배정했습니다.

배치 작업
#

간단한 배치 스크립트를 만듭니다.

#!/bin/bash
#SBATCH --job-name=hello
#SBATCH --partition=cpu
#SBATCH --nodes=1
#SBATCH --ntasks=1
#SBATCH --mem=500M
#SBATCH --time=00:05:00
#SBATCH --output=hello_%j.out

echo "Running on: $(hostname)"
echo "Job ID: $SLURM_JOB_ID"
date
sleep 10
echo "Done."

제출 및 모니터링:

$ sbatch hello.sh
Submitted batch job 1

$ squeue
JOBID PARTITION  NAME     USER  ST  TIME  NODES NODELIST
    1       cpu hello   wpaik   R  0:03      1 interceptor-01

$ cat hello_1.out
Running on: interceptor-01
Job ID: 1
Fri May  9 21:00:00 EDT 2026
Done.

멀티노드 작업
#

#!/bin/bash
#SBATCH --job-name=multinode
#SBATCH --partition=cpu
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --mem-per-cpu=1G
#SBATCH --output=multinode_%j.out

srun hostname
$ sbatch multinode.sh
Submitted batch job 2

$ cat multinode_2.out
interceptor-01
interceptor-01
interceptor-01
interceptor-01
interceptor-02
interceptor-02
interceptor-02
interceptor-02

두 개의 물리적 머신에 걸쳐 8개 태스크가 Slurm의 조율로 실행됐습니다.

GPU 작업
#

#!/bin/bash
#SBATCH --job-name=gpu_test
#SBATCH --partition=gpu
#SBATCH --nodes=1
#SBATCH --gres=gpu:1
#SBATCH --output=gpu_%j.out

nvidia-smi

seff로 효율성 확인
#

작업이 완료되면 요청한 리소스를 얼마나 효율적으로 썼는지 확인합니다.

$ seff 1
Job ID: 1
Cluster: cluster
User/Group: wpaik/wpaik
State: COMPLETED (exit code 0)
Cores: 1
CPU Utilized: 00:00:01
CPU Efficiency: 10.00% of 00:00:10 core-walltime
Job Wall-clock time: 00:00:10
Memory Utilized: 1.20 MB
Memory Efficiency: 0.24% of 500.00 MB

sleep 10이 아무것도 안 해서 CPU 효율성이 낮습니다. 500MB를 요청했지만 거의 안 써서 메모리 효율성도 낮고요. seff가 주는 피드백이 딱 이런 겁니다. 실제로 쓰는 것에 맞게 리소스 요청을 조정합니다.

9. 일반적인 문제들
#

시작 후 노드가 down 또는 drain 상태에서 멈춤

$ scontrol update NodeName=ALL State=RESUME

계속 down으로 돌아오면 해당 노드의 slurmd 로그를 확인합니다.

$ ssh interceptor-01 "sudo tail -n 50 /var/log/slurm/slurmd.log"

Slurm UID 불일치 (보안 위반)

srun이 멈추거나 로그에 인증 오류가 보이면 모든 노드의 slurm 사용자 UID가 같은지 확인합니다.

$ ansible all_nodes -m shell -a "id slurm" -b

UID가 다르면 GitHub 저장소의 08_sync_slurm_uid.yaml로 수정합니다.

MPI 작업이 PMI 오류로 실패

slurm.conf에 MpiDefault=pmix가 있는지, 컴퓨트 노드에 slurm-libpmi가 설치되어 있는지 확인합니다.

$ cat /etc/profile.d/pmix.sh
export PMIX_MCA_psec=native

slurmdbd가 시작에 실패

/etc/slurm/slurmdbd.conf 권한을 확인합니다. 모드 600이고 slurm 사용자 소유여야 합니다.

$ ls -la /etc/slurm/slurmdbd.conf
-rw------- 1 slurm slurm 312 Apr 27 09:00 /etc/slurm/slurmdbd.conf

slurmdbd 시작 전에 MariaDB가 실행 중인지도 확인합니다.

seff가 메모리 데이터를 표시하지 않음

slurm.conf에 JobAcctGatherType=jobacct_gather/cgroup이 있고 cgroup.conf에 ConstrainRAMSpace=yes가 있어야 합니다. 둘 다 cgroup v2가 필요합니다. stat -fc %T /sys/fs/cgroup으로 확인합니다.

파일이 디스크에 있는데 dnf installNo match for argument로 실패

두 가지 원인이 있는데 모두 같은 오류로 나옵니다.

  1. NFS에서 상속된 SELinux 컨텍스트. Ansible의 임시 디렉토리가 기본적으로 ~/.ansible/tmp/이고, 이 클러스터에서는 NFS 마운트된 /home에 있습니다. 여기를 통해 복사된 파일이 nfs_t SELinux 컨텍스트를 받아서 dnf가 로컬 RPM으로 조용히 처리를 거부합니다. ls -lZ /tmp/slurm_rpms/로 확인합니다. 컨텍스트가 nfs_t면 이 문제입니다. 영구 수정은 에피소드 4의 ansible.cfg에 있는 remote_tmp = /var/tmp/.ansible-${USER}/tmp 줄입니다. 즉각적인 해결책:

    sudo restorecon -Rv /tmp/slurm_rpms/
  2. 설치 전에 dnf exclude 고정이 추가된 경우. /etc/dnf/dnf.conf에 이미 exclude=slurm*이 있으면 dnf가 해당 인수를 제거하고 없다고 보고합니다. grep slurm /etc/dnf/dnf.conf로 확인합니다. 재설치의 경우 그 줄을 먼저 지우거나 --disableexcludes=all을 전달합니다.

    sudo dnf install -y --disableexcludes=all /tmp/slurm_rpms/slurm-*.rpm

dnf installnothing provides libgdk-x11-2.0.so.0 오류로 실패

실패한 노드에서 EPEL이 활성화되지 않은 겁니다. EPEL을 설치하고 재시도합니다.

```bash
sudo dnf install -y epel-release
```

또는 --without gtk로 Slurm을 재빌드해서 GTK2 의존성을 완전히 제거합니다.

10. 다음 에피소드
#

클러스터가 이제 진짜 HPC 시스템입니다. 작업이 스케줄링되고, 리소스가 추적되고, seff가 각 실행 후 효율성 데이터를 보여줍니다.

다음 에피소드에서는 Slurm 어카운팅을 심도 있게 다룹니다. slurmdbd에서 계정과 사용자 설정, 리소스 한도가 있는 파티션 설정, 그리고 무거운 사용자가 클러스터를 독점하지 못하도록 하는 페어 쉐어(Fair Share) 스케줄링입니다.

이 에피소드의 모든 Ansible 플레이북, 설정 파일, Slurm 빌드 스크립트는 GitHub 저장소에 있습니다.


즐거운 컴퓨팅 되세요!

HPC From Scratch - 이 글은 시리즈의 일부입니다.
파트 5: 이 글