AWS ParallelCluster 구축 가이드
서울 리전 · p6-b300 · 대규모 LLM 학습 환경

대상 42dot AI Infra / Data&ML 팀  ·  리전 ap-northeast-2  ·  인스턴스 p6-b300.48xlarge (8× NVIDIA B300)
규모 2노드 검증 → 16노드 파일럿 → 최대 125노드(1,000 GPU)  ·  기준 ParallelCluster 3.16.1 / Slurm 25.11.8  ·  작성 2026-09-15 (v2)
이 문서를 읽는 방법

Part 1을 먼저 읽으십시오. 특히 §4 되돌릴 수 없는 결정 7가지는 클러스터를 만든 뒤에 바꾸면 재생성이 필요한 항목입니다. Part 2는 순서대로 따라가는 절차이고, 각 단계 안에 그 단계에서 실제로 부딪히는 함정과 팁을 배치했습니다. 건너뛰지 말고 단계 내 경고 박스를 읽어주십시오.

1. 무엇을 만드는가

Slurm 스케줄러 기반의 GPU 학습 클러스터입니다. AWS ParallelCluster는 이 전체를 하나의 YAML 파일로 정의하고 CloudFormation으로 배포하는 오픈소스 도구입니다. 도구 자체는 무료이고, 생성된 AWS 리소스 비용만 청구됩니다.

┌──────────────── VPC (권장 /16) ────────────────────────────────┐ │ │ 사용자 ──SSH/SSM──────┼──▶ ┌─────────────┐ Public Subnet │ │ │ Login Nodes │ ← 사용자 접속 · sbatch/squeue │ │ │ (2대) │ │ │ └──────┬──────┘ │ │ │ │ │ ┌──────▼───────────────────┐ │ │ │ Head Node │ slurmctld (스케줄러) │ │ │ m6i.8xlarge │ clustermgtd (노드 라이프사이클)│ │ │ ⚠ 단일 장애점 │ slurmdbd (accounting) │ │ └──────┬───────────────────┘ │ │ │ Slurm 제어 │ │ ┌────────▼──────────────────────────────────────┐ │ │ │ Private Subnet (/20) · 단일 AZ · NAT 경유 │ │ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ p6-b300 #1 │ │ p6-b300 #N │ static 노드 │ │ │ │ │ 8× B300 │◀▶│ 8× B300 │ MinCount │ │ │ │ │ 16× EFA │ │ 16× EFA │ = MaxCount │ │ │ │ └──────┬──────┘ └──────┬──────┘ │ │ │ │ └── EFA 6,400 Gbps (NCCL) ──┘ │ │ │ └────────────────┬──────────────────────────────┘ │ │ │ POSIX mount │ │ ┌────────────▼─────────────┐ │ │ │ FSx for Lustre → /fsx │ ← 클러스터 외부에 생성 │ │ │ FSx for OpenZFS → /home │ (반드시) │ │ └────────────┬─────────────┘ │ └───────────────────┼────────────────────────────────────────────┘ │ DRA 동기화 ┌──────▼──────┐ ┌────────────────────┐ │ S3 (원본) │ │ Aurora MySQL │ └─────────────┘ │ (Slurm accounting) │ └────────────────────┘

2. 구성요소 개념

ParallelCluster의 리소스 계층은 다음과 같습니다. Slurm 용어와 매핑을 정확히 알아야 설정 파일이 읽힙니다.

Head Node
slurmctld(스케줄러) + clustermgtd(노드 라이프사이클 관리) + slurmdbd(accounting)를 실행합니다. NFS 서버 역할도 겸합니다. 관리형 HA가 없는 단일 장애점입니다.
Login Nodes
3.7.0부터 지원, 다중 풀(최대 10개)은 3.11.0부터. 사용자 셸 접속 전용 풀입니다. Head node를 사용자 트래픽에서 보호합니다. 노드 교체 시 GracetimePeriod만큼 사전 통보합니다.
Queue
(SlurmQueues)
Slurm partition과 1:1 대응합니다. 서브넷·placement group·구매옵션(CapacityType)·IAM을 여기서 정합니다.
Compute Resource
큐 안의 인스턴스 그룹. 인스턴스 타입 · MinCount/MaxCount · EFA · 용량 예약을 정합니다. 한 큐에 여러 compute resource를 둘 수 있습니다 — Capacity Block을 나눠 붙일 때 씁니다.
Static 노드
MinCount만큼 항상 켜져 있는 노드. 이름 규칙 <queue>-st-<computeresource>-<n>. 장애·DRAIN 시 ParallelCluster가 자동으로 교체합니다.
Dynamic 노드
MaxCount − MinCount 범위에서 job에 따라 뜨고 지는 노드. 이름 규칙 <queue>-dy-<...>. 장애 시 교체가 아니라 종료만 됩니다.
설계 결정 · 전량 static

대규모 분산학습은 MinCount == MaxCount(전량 static)로 가십시오. 두 가지 이유입니다.

  • 노드 수가 고정되어 스케줄링이 예측 가능합니다. 125노드 job이 용량 확보를 기다리다 실패하는 상황이 없습니다.
  • static 노드만 장애 시 자동 교체됩니다. 이것이 이 구성의 복원력 핵심입니다(Step 8).

Capacity Block을 쓰면 MinCount == MaxCount가 애초에 필수입니다.

3. p6-b300 하드웨어 특성

항목설계에 미치는 영향
GPU8 × NVIDIA B300, HBM 합계 2.1 TB노드 내 8 GPU가 NVLink 도메인. TP는 노드 내, PP/DP는 노드 간(EFA)
vCPU192ParallelCluster 기본값(멀티스레딩 활성)이면 Slurm에 192 CPU로 보임 → DefCPUPerGPU=24
메모리4,096 GiBDefMemPerGPU≈480GB
로컬 NVMe8 × 3,840 GBEnroot 컨테이너 오버레이 + 데이터 캐시로 활용 → Lustre 부하 감소
네트워크 카드17장 — card 0은 ENA 전용(EFA 미지원, 최대 350 Gbps), card 1–16은 EFA 각 최대 400 GbpsEFA 레이아웃 선택의 근거(§4 #4). 다중 NIC이므로 퍼블릭 IP 자동 할당이 불가 → 프라이빗 서브넷 + NAT 필수
EFA 총 대역폭6,400 GbpsNCCL 노드 간 통신
ENA 총 대역폭최대 3,870 Gbps
(EFA와 물리 리소스 공유)
기본 레이아웃에서는 primary NIC 350 Gbps만 사용 → 스토리지 병목 시 레이아웃 (B) 검토
On-Demand 단가 (서울)$209.1735 / 시간비용의 대부분. 2026-09-14 기준, Linux
참고 · SMT

ParallelCluster는 기본적으로 멀티스레딩을 끄지 않습니다(DisableSimultaneousMultithreading 기본 false). 따라서 Slurm은 192 CPU를 봅니다. 물리코어 96개 기준으로 스케줄링하려면 이 옵션을 켜고 DefCPUPerGPU12로 조정하십시오. PyTorch DataLoader(num_workers) 상한도 여기에 따라 달라집니다.

4. 되돌릴 수 없는 결정 7가지

착수 전 팀 합의 필수

아래 항목은 클러스터 생성 후 변경하면 pcluster update-cluster거부되거나 클러스터를 재생성해야 합니다. 구축을 시작하기 전에 확정하십시오.

#결정 항목왜 되돌릴 수 없나권장
1OS
Image/Os 변경불가
변경 시 클러스터 업데이트 자체가 거부됩니다 ubuntu2404 또는 alinux2023. alinux2는 3.15가 마지막 지원(AL2 EOL 2026-06-30)이라 대상이 아닙니다
2Availability Zone 변경불가 EFA는 AZ를 넘지 못합니다. 서브넷·FSx·placement group이 모두 여기에 묶입니다 서울에서 p6-b300이 실제 제공되는 AZ를 먼저 조회(Step 0)
3컴퓨트 서브넷 CIDR 확장불가 서브넷은 생성 후 크기를 늘릴 수 없습니다 /20 — #4에서 레이아웃 (B)로 전환할 여지를 남기기 위함(Step 1)
4EFA 인터페이스 레이아웃 노드당 IP 소비량과 스토리지 대역폭이 여기서 갈립니다. #3에 종속 (A) 기본값으로 시작 → 스토리지 병목 확인 시 (B)로 전환(Step 5d)
5용량 확보 경로
Capacity Block vs ODCR
MinCount/MaxCount 제약과 노드 수명이 완전히 달라집니다 Step 0 · Step 5d
6공유 스토리지를
클러스터 외부에 생성
치명적
ParallelCluster는 마이너 버전 업그레이드가 클러스터 재생성입니다. 클러스터 정의 안에서 FSx를 만들면 그때 데이터가 함께 삭제됩니다 FSx를 별도로 만들고 FileSystemId로 참조(Step 2)
7ParallelCluster 버전 각 마이너 버전이 CLI와 self-contained. 버전 이동 = 클러스터 재생성 착수 시점의 최신 안정 릴리스. 이 문서는 3.16.1 기준으로 작성했으나 CHANGELOG에 3.17.0이 이미 올라와 있습니다. 한 단계 뒤 버전으로 새 클러스터를 만들면 곧 재생성(#6)이 필요해집니다. p6-b300은 3.15.0 이상 필수 착수 시 확인
#6이 이 문서에서 가장 중요한 항목입니다

3.16 → 3.17로 올릴 때 클러스터를 다시 만들어야 합니다. 이때 FSx/EFS를 클러스터 정의 안에서 만들었다면 학습 데이터와 체크포인트가 사라집니다.

외부에 만들고 ID로 참조하면 이렇게 무중단에 가깝게 이관됩니다.

  1. 새 버전 CLI로 새 클러스터를 병렬 생성 → 같은 파일시스템 연결
  2. 데이터·애플리케이션 검증
  3. 검증 완료 후 기존 클러스터만 삭제

5. 설계 요약

영역결정근거 / 상세
AMI공식 AMI 사용, 커스텀 AMI 만들지 않음NVIDIA 595.71.05 · CUDA 13.2.2 · DCGM 4.6.0 · EFA 1.49.0 · GDRCopy 2.6 · Enroot 4.2.1 + Pyxis 0.24.0 · Slurm 25.11.8 · Lustre 클라이언트가 이미 포함. 추가 설치는 CustomActions로(Step 3)
EFAEfa: Enabled: true 한 줄3.15.0+ 가 인스턴스 타입에 맞춰 EFA-only 인터페이스를 자동 구성. 노드당 IP ≈ 1개
네트워크컴퓨트는 프라이빗 서브넷 + NAT, AssignPublicIp: false다중 NIC 인스턴스는 퍼블릭 IP 자동 할당 불가 → 부트스트랩 실패 방지
노드 구성전량 static (MinCount == MaxCount)예측 가능한 스케줄링 + 장애 자동 교체
GPU 헬스체크내장 체크 비활성 + 3단계 자체 구성AWS 문서가 p6 계열에서 HealthChecks/Gpu/Enabled: false를 지시(Step 8)
스토리지/fsx Lustre + /home OpenZFS + 로컬 NVMe 캐시 + S3클러스터 외부 생성 후 ID 참조
멀티팀파티션 + Slurm accounting QoS파티션만으로는 독점을 막을 수 없음. GrpTRES=gres/gpu=N이 실제 강제 수단(Step 7)
관측CloudWatch 기본 + AMP/AMG 관리형 Prometheus/Grafanaself-host하면 노드 교체 시 과거 메트릭 소실
확장2 → 16 → 최대 125노드MinCount/MaxCount 증가는 fleet 정지 불필요(Step 10)

Part 2 · 구축 절차

STEP 0

용량과 쿼터 확보

D-14 ~ D-7

일정상 가장 앞에 와야 하는 단계입니다. 다른 모든 작업이 여기에 의존합니다.

0-1. p6-b300 가용 AZ 조회

aws ec2 describe-instance-type-offerings --region ap-northeast-2 \
  --location-type availability-zone \
  --filters Name=instance-type,Values=p6-b300.48xlarge \
  --query 'InstanceTypeOfferings[].Location' --output table

여기서 나온 AZ가 이후 서브넷·FSx·placement group의 위치를 전부 결정합니다.

0-2. 용량 예약 — 두 경로 중 선택

경로특징제약적합
Capacity Block
for ML
기간 예약. UltraCluster 내 근접 배치 자동. ParallelCluster가 Slurm reservation 라이프사이클을 자동 관리 블록당 최대 64대 · 전체 Capacity Block 합계 256대(계정/조직 기준인지 확인 필요) · MinCount==MaxCount>0 필수 · 취소 불가 · 최대 8주 전 예약 기간이 정해진 대규모 학습 캠페인
ODCR
(targeted)
기간 제약 없음. 장기 상시 운영 Running On-Demand P instances vCPU 쿼터 필요 상시 운영 · 개발용 소규모
함정 · 125노드는 단일 Capacity Block으로 불가능

Capacity Block은 블록당 최대 64대입니다. 125노드를 Capacity Block으로 확보하려면 블록이 최소 2개 필요하고, ParallelCluster에서는 블록마다 별도 compute resource로 정의합니다. 두 compute resource를 같은 큐에 매핑하면 사용자에게는 하나의 파티션으로 보이므로 실사용에는 영향이 없습니다.

추가로 AWS 문서에 "Capacity Block sizes of 64 instances are not supported for all instance types in all AWS Regions"라는 단서가 있습니다. 서울 p6-b300의 실제 최대 블록 크기를 확인하십시오 — 32대라면 compute resource가 4개가 됩니다. 확인 필요

함정 · Capacity Block 종료 시각은 UTC 고정 (KST 20:00)

Capacity Block은 UTC 11:30에 종료되고, 마지막 날 UTC 11:00부터 인스턴스 종료 프로세스가 시작됩니다. KST 기준 20:00 종료 시작 / 20:30 완료입니다.

학습 스크립트가 KST 19:30 이전에 최종 체크포인트를 저장하도록 계획하십시오. 예약 창 전체가 과금되고 조기 취소는 불가능합니다.

0-3. EC2 쿼터 신청

경로필요 쿼터125노드 기준
ODCR / On-DemandRunning On-Demand P instances (vCPU 기준)24,000 vCPU
Capacity Block위 쿼터에 계산되지 않음. 전체 CB 합계 한도(256대)만 적용256대 한도 내
팁 · 쿼터를 지금 신청하십시오

승인 리드타임이 이 프로젝트에서 가장 긴 대기 항목입니다. Capacity Block만 쓸 계획이면 불필요하지만, 두 경로를 섞을 가능성이 조금이라도 있으면 지금 신청하는 게 안전합니다. 쿼터는 확보만 해두고 쓰지 않아도 비용이 발생하지 않습니다.

0-4. 도구 준비

pip install aws-parallelcluster==3.16.1
pcluster version
참고 · CLI 권한

3.16.0부터 CLI가 tag:GetResources 권한을 추가로 요구합니다(login node 로드밸런서 조회용). 기존 IAM 정책을 재사용한다면 이 권한을 추가하십시오.

STEP 1

네트워크 구축

D-7

1-1. 만들 것

  • VPC — 권장 /16, DNS hostnames + DNS resolution 활성
  • 퍼블릭 서브넷 1개 — head node, login nodes
  • 프라이빗 서브넷 1개 (컴퓨트 전용) — Step 0에서 확인한 AZ, 크기는 아래 표
  • NAT Gateway — 컴퓨트 서브넷 라우팅 테이블에 경로 추가
  • (선택) S3 / ECR / CloudWatch VPC 엔드포인트 — NAT 데이터 처리 비용 절감

1-2. 컴퓨트 서브넷 사이징

EFA 레이아웃(Step 5d)에 따라 노드당 IP 소비가 달라집니다.

GPU 노드레이아웃 (A) 기본
노드당 ~1 IP
(A) 최소 서브넷레이아웃 (B) use case 2
노드당 17 IP
(B) 최소 서브넷
2~2/2834/26
16~16/27272/23
32~32/26544/22
64~64/251,088/21
125~125/242,125/20
팁 · 그냥 /20으로 잡으십시오

기본 레이아웃이면 /24로 충분하지만, 서브넷은 나중에 키울 수 없고 IP는 비용이 들지 않습니다. 레이아웃 (B)로 전환할 가능성을 열어두려면 처음부터 /20이 안전합니다.

head node · login node · FSx 마운트타깃은 별도 서브넷으로 분리하십시오.

함정 · 컴퓨트를 퍼블릭 서브넷에 두면 부트스트랩이 실패합니다

EC2는 네트워크 인터페이스가 2개 이상인 인스턴스에 퍼블릭 IP를 자동 할당하지 않습니다. EFA를 켠 컴퓨트 노드는 항상 다중 인터페이스로 뜨므로, 퍼블릭 서브넷 + 자동 퍼블릭 IP로 인터넷을 쓰려 하면 노드가 부트스트랩에 실패합니다.

→ 컴퓨트는 프라이빗 서브넷 + NAT Gateway, 설정에 AssignPublicIp: false명시하십시오. ParallelCluster 3.16.0의 검증기가 이 조건을 단일 네트워크카드 + EFA 조합까지 확장해 검사합니다.

참고 · EFA는 AZ를 넘지 못합니다

컴퓨트 큐의 SubnetIds항상 1개(단일 AZ)로 두십시오. 여러 AZ에 걸치면 노드 간 EFA 통신이 동작하지 않습니다.

STEP 2

공유 스토리지 생성 — 클러스터 외부에

D-5
이 단계를 클러스터 생성 전에 하는 이유

ParallelCluster는 마이너 버전 업그레이드가 클러스터 재생성입니다. 클러스터 정의 안에서 FSx를 만들면 클러스터를 삭제할 때 파일시스템도 함께 삭제됩니다. 반드시 먼저 따로 만들고 클러스터 설정에서는 ID로만 참조하십시오. AWS 문서의 명시적 권고이기도 합니다.

2-1. 계층 구조

마운트서비스용도
/fsxFSx for Lustre
PERSISTENT_2, PerUnitStorageThroughput 250 이상
학습 데이터, 체크포인트, 컨테이너 .sqsh 이미지
/homeFSx for OpenZFS 또는 EFS홈 디렉터리 (small file / metadata 위주)
/opt/dlami/nvme로컬 NVMe (8 × 3.84 TB)Enroot 오버레이, 데이터셋 로컬 캐시 — 휘발성
S3 (+ Lustre DRA)원본 데이터셋, 체크포인트 아카이브

2-2. 만들 때 지킬 것

  • FSx for Lustre를 컴퓨트와 같은 AZ에 생성 (AZ 간 전송 비용·지연 회피)
  • 파일시스템 보안그룹에 컴퓨트 / head / login 인바운드 허용
  • S3 버킷 생성 + Lustre DRA(Data Repository Association) 연동
팁 · 작게 만들고 나중에 늘리십시오

FSx for Lustre와 OpenZFS 모두 생성 후 용량·처리량 증설이 가능합니다(데이터 마이그레이션 없음). 큰 파일시스템은 생성 자체에 시간이 오래 걸려 초기 구축 전체를 지연시킵니다. 최소 근처에서 시작해 클러스터가 뜬 뒤 확장하십시오.

참고 · GPUDirect Storage

FSx for Lustre에 EFA를 켜면 GPU 메모리로 직접 DMA하는 GDS 경로를 쓸 수 있습니다. 다만 PERSISTENT_2 SSD 전용이고 최소 용량이 크게 올라갑니다(PerUnitStorageThroughput=250에서 19,200 GiB). p6-b300에서의 GDS 지원 여부는 확인이 필요합니다 확인 필요 — 1단계에서는 켜지 말고, 스토리지가 실제 병목으로 확인된 뒤 검토하십시오.

STEP 3

부트스트랩 스크립트 준비

D-5
설계 원칙 · 커스텀 AMI 대신 CustomActions

공식 AMI에 이미 NVIDIA 드라이버 · CUDA · DCGM · EFA · GDRCopy · Enroot/Pyxis · Slurm · Lustre 클라이언트가 들어 있습니다. 추가로 필요한 것은 CustomActions 부트스트랩 스크립트로 넣으십시오.

AWS 문서가 커스텀 AMI보다 이 방식을 권장하는 이유는 커스텀 AMI를 쓰면 ParallelCluster 릴리스마다 AMI를 다시 만들어야 하기 때문입니다. 부팅 시간이 문제가 될 만큼 설치량이 늘어난 다음에 커스텀 AMI를 검토하는 순서가 맞습니다.

3-1. 스크립트 목록과 실행 지점

스크립트실행 지점내용
head-setup.shHead OnNodeConfigured디렉터리별 Lustre striping(3-2, 1회), /fsx/ops 골격 생성, 운영 도구 설치
login-setup.shLogin OnNodeConfigured사용자 도구(enroot 설정, 모듈, 셸 배너), /home 마운트 확인
compute-start.shOnNodeStart
(노드 셋업 전)
needrestart 가드(아래 참조) + 헬스체크 스크립트를 S3에서 로컬 /opt/ops/health로 복사(Step 8, prolog/epilog는 반드시 로컬 디스크에서 실행)
lustre-tuning.shOnNodeConfiguredLustre 런타임 파라미터(3-2)
gpu-healthcheck-startup.shOnNodeConfigured심층 GPU 진단 — 노드 기동 시 1회(Step 8)
dcgm-exporter.shOnNodeConfiguredDCGM exporter + node_exporter 기동(Step 5e)

S3 버킷에 업로드하고, head/compute/login IAM에 해당 버킷 읽기 권한을 부여합니다.

3-2. Lustre 런타임 튜닝 — 기본값은 대규모 GPU에 맞지 않습니다

# 데이터 경로 (OSC) — 체크포인트 쓰기 처리량
lctl set_param osc.*.max_rpcs_in_flight=32       # 기본 8
lctl set_param osc.*.max_dirty_mb=512            # 기본 32
lctl set_param osc.*.max_pages_per_rpc=1024      # 기본 256(1MB) → 4MB/RPC

# 메타데이터 경로 (MDC) — Python import, HF 캐시 walk에 결정적
lctl set_param mdc.*.max_rpcs_in_flight=64
lctl set_param mdc.*.max_mod_rpcs_in_flight=32

# read-ahead (llite) — 4TB 메모리 노드에서는 크게 잡아도 무리 없음
lctl set_param llite.*.max_read_ahead_mb=1024
lctl set_param llite.*.statahead_max=512

디렉터리별 striping은 login/head 노드에서 1회만 실행합니다.

lfs setstripe -c -1 -S 4M /fsx/checkpoints   # 전 OST 분산 — 대용량 순차 쓰기
lfs setstripe -c -1 -S 4M /fsx/datasets      # 전 노드 순차 읽기
lfs setstripe -c 8  -S 4M /fsx/containers    # .sqsh 이미지 (5–30 GB)
lfs setstripe -c 1        /fsx/logs          # small append — 넓게 펴면 lock 오버헤드만 증가
팁 · 튜닝 효과를 측정해서 기록하십시오

적용 전/후 체크포인트 쓰기 처리량을 비교해 수치로 남기십시오. 이후 노드 교체나 확장 후 회귀를 판정하는 기준선이 됩니다. 마운트 옵션에는 noatime을 권장합니다.

함정 · slurmd 자동 재시작으로 job이 전멸할 수 있습니다 (Ubuntu)

Ubuntu 계열에서 unattended security upgrade가 slurmd가 링크한 라이브러리(glibc 등)를 갱신하면, needrestartslurmd를 재시작하고 그 노드에서 실행 중인 모든 job이 죽습니다. 무작위가 아니라 재현되는 현상입니다. 며칠짜리 학습에서는 치명적입니다.

ParallelCluster 3.16.1에서 이 시나리오가 방어되는지는 확인이 필요합니다 확인 필요. 확인 전이라면 OnNodeStart에 드롭인을 넣어두는 것이 안전합니다.

# /etc/needrestart/conf.d/90-slurm.conf
$nrconf{override_rc}{qr(^slurmd)} = 0;

보안 업데이트는 계속 설치되고 slurmd 재시작만 유보됩니다.

STEP 4

Accounting DB 준비 (멀티팀 운영 시)

D-3

ParallelCluster의 Slurm accounting은 고객이 MySQL 호환 DB를 준비해야 합니다. 팀별 GPU 쿼터를 강제하려면 필수입니다.

방식구성권장 상황
SlurmSettings/Database
(3.3.0+)
slurmdbdhead node에서 구동, 외부 DB에 연결단일 클러스터 — 이 구성에 권장
SlurmSettings/ExternalSlurmdbd
(3.10.0+)
slurmdbd별도 인스턴스로 분리여러 클러스터가 DB 공유 시
  • Amazon Aurora MySQL 또는 RDS MySQL 생성 (head node에서 도달 가능한 위치)
  • DB 자격증명을 Secrets Manager에 저장 → ARN 확보
  • head node IAM에 해당 시크릿 읽기 권한 부여
  • DB 보안그룹에 head node 인바운드 3306 허용
함정 4가지
  • head node 부하가 커집니다. accounting을 켜면 CPU·메모리·네트워크 사양을 올려야 합니다(AWS 문서 권고).
  • accounting 엔티티는 고객이 직접 관리합니다. ParallelCluster는 기본 부트스트랩만 하고 계정·사용자·QoS를 만들어주지 않습니다.
  • ExternalSlurmdbd를 쓰면 클러스터 이름이 40자 이하여야 합니다(MySQL 테이블명 길이 제약). 또한 그 구간 트래픽은 암호화되지 않습니다 — 신뢰된 네트워크에서만 운영하십시오.
  • DB 비밀번호를 변경할 때는 compute fleet을 먼저 정지하십시오(accounting 데이터 손실 방지).
팁 · 지금 안 켜도 됩니다

2노드 검증 단계에서는 accounting 없이 진행해도 됩니다. 다만 파티션 AllowQOS를 쓰려면 accounting이 먼저 있어야 하므로(Step 7), 멀티팀 운영이 확정이면 처음부터 켜는 편이 순서가 깔끔합니다.

단, AccountingStorageEnforce=associations를 켠 순간 sacctmgr에 등록되지 않은 사용자는 제출 자체가 거부됩니다. accounting을 켜기 전에 사용자 목록을 준비하고, 켠 직후 바로 계정·사용자 등록(7-3)을 하십시오.

STEP 5

cluster-config.yaml 작성

D-2

블록별로 나눠 설명합니다. 각 블록 아래에 그 설정에서 실제로 문제가 되는 항목을 붙였습니다. 5f에 2노드 검증용 전체 파일을 실었습니다.

5a. Region / Image / HeadNode

Region: ap-northeast-2

Image:
  Os: ubuntu2404              # ⚠ 변경 불가 — 되돌릴 수 없는 결정 #1

HeadNode:
  InstanceType: m6i.8xlarge
  Ssh:
    KeyName: ${SSH_KEY}
    AllowedIps: ${TRUSTED_CIDR}     # 0.0.0.0/0 금지
  Networking:
    SubnetId: ${PUBLIC_SUBNET_ID}
  LocalStorage:
    RootVolume:
      Size: 1024
      VolumeType: gp3
      Iops: 16000
      Throughput: 1000
  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
    S3Access:
      - BucketName: ${SCRIPT_BUCKET}
        EnableWriteAccess: false
  CustomActions:
    OnNodeConfigured:
      Script: s3://${SCRIPT_BUCKET}/head-setup.sh
함정 · Head Node는 단일 장애점입니다

slurmctld(스케줄러) + clustermgtd(노드 라이프사이클) + slurmdbd(accounting)가 모두 여기서 돕니다. 관리형 HA가 없습니다. Head node가 죽으면 실행 중인 job은 계속 돌지만, 신규 제출·스케줄링·노드 스케일링이 멈춥니다.

완화책 4가지

  • 사양을 넉넉히. Head node는 스케일링 오케스트레이션 + NFS 서버 역할을 겸합니다. AWS 문서가 "노드 수가 많으면 head node에 여유 컴퓨트를 주라"고 권고합니다. 16노드에 m6i.8xlarge, 125노드로 확장할 때 재검토하십시오. accounting을 켜면 더 올려야 합니다.
  • 사용자를 login node로 분리(5b) — head node를 셸 접속에서 보호합니다.
  • 중요 데이터를 head node에 두지 마십시오. /home을 FSx OpenZFS/EFS로 외부화하십시오.
  • Head node 상태에 CloudWatch 알람을 걸어두십시오.
함정 · IAM에 AdministratorAccess를 붙이지 마십시오

공개된 일부 예제(AWS 블로그 포함)가 head/compute 노드에 AdministratorAccess를 붙입니다. 따라 하지 마십시오. 실제로 필요한 것은 S3 스크립트 읽기, CloudWatch 쓰기, (accounting 시) Secrets Manager 읽기, SSM 정도입니다.

5b. LoginNodes

LoginNodes:
  Pools:
    - Name: login
      Count: 2
      InstanceType: m6i.4xlarge
      GracetimePeriod: 30          # 노드 교체 전 사용자 사전 통보 (분, 3~120)
      Networking:
        SubnetIds: [${PUBLIC_SUBNET_ID}]   # 풀당 서브넷 1개만
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      CustomActions:
        OnNodeConfigured:
          Script: s3://${SCRIPT_BUCKET}/login-setup.sh
팁 · login node를 반드시 두십시오

사용자가 head node에 직접 붙으면 잘못된 명령 하나가 스케줄러 전체를 흔들 수 있습니다. Login node는 3.11.0부터 최대 10개 풀을 만들 수 있습니다. 접속은 SSH 대신 SSM Session Manager를 쓰면 인바운드 포트를 열지 않아도 됩니다.

5c. SlurmSettings

Scheduling:
  Scheduler: slurm
  SlurmSettings:
    ScaledownIdletime: 60
    QueueUpdateStrategy: DRAIN
    EnableMemoryBasedScheduling: true
    CustomSlurmSettingsIncludeFile: s3://${SCRIPT_BUCKET}/slurm-extra.conf
    Database:                          # Step 4에서 준비
      Uri: ${AURORA_ENDPOINT}:3306
      UserName: ${DB_USER}
      PasswordSecretArn: ${SECRET_ARN}
설정왜 이 값인가
EnableMemoryBasedScheduling: true끄면 Slurm이 CPU만 보고 배치해 메모리 부족이 발생할 수 있습니다. GPU 노드에서는 반드시 켜십시오.
QueueUpdateStrategy: DRAIN클러스터 업데이트 시 실행 중 job을 보존하며 노드를 순차 교체합니다.
CustomSlurmSettingsIncludeFileS3의 include 파일을 slurm.conf에 그대로 반영합니다. 파티션·QoS·fair-share·prolog/epilog를 여기서 정의합니다(Step 7). 파라미터 제한이 없습니다.

5d. GPU 큐 — 이 문서에서 가장 중요한 블록

먼저 EFA 레이아웃을 선택하십시오.

 (A) 기본값 권장(B) use case 2
설정Efa: Enabled: true 한 줄LaunchTemplateOverrides로 33개 인터페이스 정의
EFA 대역폭6,400 Gbps6,400 Gbps
ENA 대역폭primary NIC 최대 350 Gbps최대 3,870 Gbps
노드당 사설 IP~1개17개
선택 기준대부분의 경우FSx Lustre 대역폭이 실측으로 병목일 때만

(A) 기본 레이아웃 설정입니다.

  SlurmQueues:
    - Name: gpu
      CapacityType: ONDEMAND            # 또는 CAPACITY_BLOCK
      JobExclusiveAllocation: false
      CustomSlurmSettings:                # ⚠ 이 큐가 만드는 'gpu' 파티션을 잠금 (Step 7 참조)
        Hidden: YES
        AllowGroups: root
      HealthChecks:
        Gpu:
          Enabled: false              # ⚠ p6-b300에서는 반드시 false
      Networking:
        SubnetIds: [${PRIVATE_SUBNET_ID}]  # 단일 AZ
        AssignPublicIp: false           # ⚠ EFA 다중 NIC → 필수
        PlacementGroup:
          Enabled: true                # CAPACITY_BLOCK이면 false
      ComputeSettings:
        LocalStorage:
          EphemeralVolume:
            MountDir: /opt/dlami/nvme    # 로컬 NVMe 활용
          RootVolume:
            Size: 500
            VolumeType: gp3
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        S3Access:
          - BucketName: ${SCRIPT_BUCKET}
            EnableWriteAccess: false
      ComputeResources:
        - Name: b300
          InstanceType: p6-b300.48xlarge
          MinCount: 2                  # 전량 static — 2노드 검증 → 16 → 125 순으로 증가
          MaxCount: 2
          Efa:
            Enabled: true              # 3.15.0+ 가 EFA-only 자동 구성
          CapacityReservationTarget:
            CapacityReservationId: ${CRID}
      CustomActions:
        OnNodeStart:
          Script: s3://${SCRIPT_BUCKET}/compute-start.sh
        OnNodeConfigured:
          Sequence:
            - Script: s3://${SCRIPT_BUCKET}/lustre-tuning.sh
            - Script: s3://${SCRIPT_BUCKET}/gpu-healthcheck-startup.sh
            - Script: s3://${SCRIPT_BUCKET}/dcgm-exporter.sh
함정 · 내장 GPU health check를 켜면 정상 노드가 drain됩니다

AWS 문서 원문입니다.

on the P6 and P6e GPU instance families (for example, p6-b200 and p6-b300) and later P-family GPU instance generations, the diagnostic takes long enough that it should not be run in the prolog: it typically exceeds the Slurm prolog's time limits and causes healthy nodes to be drained and jobs to be requeued. On these instance types, keep the GPU health check disabled.

내장 체크는 Slurm prolog에서 DCGM level-2 진단을 돌립니다. p6-b300의 복잡한 GPU 토폴로지 때문에 진단이 prolog 시간 제한을 초과합니다. HealthChecks/Gpu/Enabled: false로 두고, Step 8의 3단계 방식으로 대체하십시오.

함정 · 큐 이름이 곧 파티션입니다 — 잠그지 않으면 QoS를 우회합니다

SlurmQueues.Name: gpu는 그 자체로 PartitionName=gpu를 만들고, 여기에는 AllowQOS가 없습니다. Step 7에서 debug/normal/large/exclusive 파티션에 QoS를 걸어도 사용자가 -p gpu로 제출하면 모든 제한을 건너뜁니다. 또 ParallelCluster는 첫 큐의 파티션을 Default=YES로 만들기 때문에 include 파일의 기본 파티션과 충돌할 수 있습니다.

→ 위 YAML처럼 큐 레벨 CustomSlurmSettingsHidden=YES + AllowGroups=root를 걸어 일반 사용자에게서 숨기십시오. 큐 레벨에서 Nodes·PartitionName·State는 deny list라 쓸 수 없습니다. 클러스터가 뜬 뒤 scontrol show partition | grep -E 'PartitionName|Default'기본 파티션이 normal인지 확인하십시오(Step 9).

함정 · JobExclusiveAllocation과 dcgmi diag를 함께 쓰지 마십시오

JobExclusiveAllocation: false(노드 공유 허용)는 활용률을 올려주지만, 노드를 여러 job이 공유하는 상태에서 dcgmi diag(level 1~4 전부)를 돌리면 진단이 실패하고 노드가 drain됩니다.

→ 심층 진단은 job이 없는 시점(노드 기동 시 OnNodeConfigured, 또는 정비 창)에만 돌리십시오. prolog에는 nvidia-smi 수준의 수 초짜리 체크만 넣습니다.

함정 · Capacity Block에서는 placement group을 지정할 수 없습니다

EC2 문서 명시: "Capacity Blocks do not support placement groups." Capacity Block을 쓸 때는 PlacementGroup: { Enabled: false }로 두십시오. 근접 배치는 UltraCluster가 자체적으로 처리합니다.

반대로 On-Demand/ODCR 경로에서는 반드시 Enabled: true로 켜십시오 — 안 켜면 노드가 흩어져 EFA 지연이 늘어납니다.

Capacity Block 경로라면 큐 블록이 이렇게 바뀝니다. 아래는 달라지는 부분만 적은 것이며, CustomSlurmSettings·HealthChecks·ComputeSettings·Iam·CustomActions는 위 (A) 블록과 동일하게 유지합니다.

    - Name: gpu
      CapacityType: CAPACITY_BLOCK
      Networking:
        SubnetIds: [${PRIVATE_SUBNET_ID}]
        AssignPublicIp: false
        PlacementGroup:
          Enabled: false              # CB는 PG 불가
      ComputeResources:
        - Name: b300-cb1                # 블록당 최대 64대 →
          InstanceType: p6-b300.48xlarge
          MinCount: 64                  # MinCount == MaxCount 필수
          MaxCount: 64
          Efa: { Enabled: true }
          CapacityReservationTarget:
            CapacityReservationId: cr-xxxxxxxx
        - Name: b300-cb2                # 125노드는 CB 2개 = CR 2개
          InstanceType: p6-b300.48xlarge
          MinCount: 61
          MaxCount: 61
          Efa: { Enabled: true }
          CapacityReservationTarget:
            CapacityReservationId: cr-yyyyyyyy
팁 · ParallelCluster가 Capacity Block 라이프사이클을 자동 관리합니다
  • CB가 아직 active가 아니어도 클러스터가 생성됩니다. 해당 노드는 Slurm reservation/maintenance 상태로 대기하며, job을 받되 pending에 머뭅니다.
  • CB 시작 시각에 reservation이 자동 해제되고 인스턴스가 올라옵니다.
  • CB 종료 시각에 노드가 다시 maintenance로 돌아갑니다. 이후 job 재제출은 사용자 책임입니다.

5e. 스토리지 / 관측 / 타임아웃

SharedStorage:
  - Name: fsx
    MountDir: /fsx
    StorageType: FsxLustre
    FsxLustreSettings:
      FileSystemId: ${FSX_ID}          # ⚠ 외부 생성한 것을 ID로 참조
  - Name: home
    MountDir: /home
    StorageType: FsxOpenZfs
    FsxOpenZfsSettings:
      VolumeId: ${OPENZFS_VOLUME_ID}

Monitoring:
  DetailedMonitoring: true
  Logs:
    CloudWatch:
      Enabled: true
      RetentionInDays: 90
  Dashboards:
    CloudWatch:
      Enabled: true

DevSettings:
  Timeouts:
    HeadNodeBootstrapTimeout: 3600    # 기본값은 부족할 수 있음
    ComputeNodeBootstrapTimeout: 3600

Tags:
  - Key: Project
    Value: llm-training
팁 · 부트스트랩 타임아웃을 늘려두십시오

다중 파일시스템 마운트 + 부트스트랩 스크립트 + 심층 GPU 진단이 겹치면 기본 타임아웃으로는 부족할 수 있습니다. 3600초로 시작해서 실측 후 줄이십시오. 타임아웃으로 클러스터 생성이 실패하면 원인 파악에 시간이 많이 듭니다.

참고 · GPU 메트릭은 DCGM이 이미 있습니다

공식 AMI에 DCGM 4.6.0이 포함되어 있으므로 dcgm-exporter만 띄우면 됩니다(OnNodeConfigured). 수집 경로는 Amazon Managed Service for Prometheus → Amazon Managed Grafana(둘 다 서울 지원)를 권장합니다.

Prometheus/Grafana를 head node나 login node에 self-host하면 그 노드가 교체될 때 과거 메트릭과 커스텀 대시보드가 사라집니다(TSDB가 노드 로컬). 장기 학습 운영에서는 관리형이 안전합니다.

팁 · EFA 대시보드를 꼭 만드십시오

17-NIC 구성이 실제로 다 붙어 동작하는지, RDMA read/write와 drop packet이 정상인지 확인하는 유일한 상시 수단입니다. NCCL 성능이 갑자기 떨어졌을 때 가장 먼저 보는 대시보드가 됩니다.

5f. 전체 파일 — 2노드 검증용 cluster-config.yaml

위 블록을 합친 파일입니다. ${...}는 실제 값으로 치환하십시오. 16노드로 갈 때는 MinCount/MaxCountslurm-extra.confNodes= 범위만 바뀝니다.

Region: ap-northeast-2

Image:
  Os: ubuntu2404

HeadNode:
  InstanceType: m6i.8xlarge
  Ssh:
    KeyName: ${SSH_KEY}
    AllowedIps: ${TRUSTED_CIDR}
  Networking:
    SubnetId: ${PUBLIC_SUBNET_ID}
  LocalStorage:
    RootVolume: { Size: 1024, VolumeType: gp3, Iops: 16000, Throughput: 1000 }
  Iam:
    AdditionalIamPolicies:
      - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
    S3Access:
      - { BucketName: ${SCRIPT_BUCKET}, EnableWriteAccess: false }
  CustomActions:
    OnNodeConfigured:
      Script: s3://${SCRIPT_BUCKET}/head-setup.sh

LoginNodes:
  Pools:
    - Name: login
      Count: 2
      InstanceType: m6i.4xlarge
      GracetimePeriod: 30
      Networking:
        SubnetIds: [${PUBLIC_SUBNET_ID}]
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      CustomActions:
        OnNodeConfigured:
          Script: s3://${SCRIPT_BUCKET}/login-setup.sh

Scheduling:
  Scheduler: slurm
  SlurmSettings:
    ScaledownIdletime: 60
    QueueUpdateStrategy: DRAIN
    EnableMemoryBasedScheduling: true
    CustomSlurmSettingsIncludeFile: s3://${SCRIPT_BUCKET}/slurm-extra.conf
    Database:                          # accounting 미사용 시 이 블록 삭제
      Uri: ${AURORA_ENDPOINT}:3306
      UserName: ${DB_USER}
      PasswordSecretArn: ${SECRET_ARN}
  SlurmQueues:
    - Name: gpu
      CapacityType: ONDEMAND
      JobExclusiveAllocation: false
      CustomSlurmSettings:
        Hidden: YES
        AllowGroups: root
      HealthChecks:
        Gpu: { Enabled: false }
      Networking:
        SubnetIds: [${PRIVATE_SUBNET_ID}]
        AssignPublicIp: false
        PlacementGroup: { Enabled: true }
      ComputeSettings:
        LocalStorage:
          EphemeralVolume: { MountDir: /opt/dlami/nvme }
          RootVolume: { Size: 500, VolumeType: gp3 }
      Iam:
        AdditionalIamPolicies:
          - Policy: arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        S3Access:
          - { BucketName: ${SCRIPT_BUCKET}, EnableWriteAccess: false }
      ComputeResources:
        - Name: b300
          InstanceType: p6-b300.48xlarge
          MinCount: 2
          MaxCount: 2
          Efa: { Enabled: true }
          CapacityReservationTarget:
            CapacityReservationId: ${CRID}
      CustomActions:
        OnNodeStart:
          Script: s3://${SCRIPT_BUCKET}/compute-start.sh
        OnNodeConfigured:
          Sequence:
            - Script: s3://${SCRIPT_BUCKET}/lustre-tuning.sh
            - Script: s3://${SCRIPT_BUCKET}/gpu-healthcheck-startup.sh
            - Script: s3://${SCRIPT_BUCKET}/dcgm-exporter.sh

SharedStorage:
  - Name: fsx
    MountDir: /fsx
    StorageType: FsxLustre
    FsxLustreSettings: { FileSystemId: ${FSX_ID} }
  - Name: home
    MountDir: /home
    StorageType: FsxOpenZfs
    FsxOpenZfsSettings: { VolumeId: ${OPENZFS_VOLUME_ID} }

Monitoring:
  DetailedMonitoring: true
  Logs:
    CloudWatch: { Enabled: true, RetentionInDays: 90 }
  Dashboards:
    CloudWatch: { Enabled: true }

DevSettings:
  Timeouts:
    HeadNodeBootstrapTimeout: 3600
    ComputeNodeBootstrapTimeout: 3600

Tags:
  - { Key: Project, Value: llm-training }
STEP 6

클러스터 생성

D-day
# 1) 설정 검증만 — 리소스를 만들지 않습니다. 반드시 먼저 실행하십시오.
pcluster create-cluster -n llm-poc -c cluster-config.yaml --dryrun true

# 2) 생성 (2노드 검증 구성으로 시작)
pcluster create-cluster -n llm-poc -c cluster-config.yaml

# 3) 상태 확인
pcluster describe-cluster -n llm-poc

# 4) 실패 시 로그
pcluster list-cluster-log-streams -n llm-poc
pcluster get-cluster-log-events -n llm-poc --log-stream-name <stream>
팁 · --dryrun을 습관화하십시오

ParallelCluster의 검증기가 인스턴스 타입 · EFA 조합 · 네트워크 인터페이스 · 서브넷 · IAM을 사전 점검합니다. 특히 다중 NIC + 퍼블릭 IP 조합은 이 단계에서 걸러집니다. 생성 후 실패하면 롤백에 시간이 듭니다.

팁 · 2노드로 시작하십시오

16노드 이상으로 바로 가지 마십시오. 설정 오류 하나가 노드 수만큼 비용으로 곱해집니다. 2노드로 Step 9의 검증을 전부 통과시킨 뒤 MinCount/MaxCountslurm-extra.conf의 파티션 Nodes= 범위를 올리면 됩니다(fleet 정지 불필요).

접속

# login node 인스턴스 ID 확인 후 SSM 세션
aws ec2 describe-instances --region ap-northeast-2 \
  --filters "Name=tag:parallelcluster:cluster-name,Values=llm-poc" \
            "Name=tag:parallelcluster:node-type,Values=LoginNode" \
            "Name=instance-state-name,Values=running" \
  --query 'Reservations[].Instances[].InstanceId' --output text

aws ssm start-session --target <instance-id> --region ap-northeast-2
STEP 7

파티션과 QoS — 멀티팀 운영

D+1
함정 · 순서를 어기면 Slurm이 설정을 적용하지 못합니다

파티션의 AllowQOS에 쓰는 QoS는 accounting DB에 먼저 존재해야 합니다. 반드시 이 순서로 진행하십시오.

① accounting 활성(Step 4) → ② sacctmgr로 계정·사용자·QoS 생성 → ③ include 파일에 파티션 AllowQOS 작성 → ④ 클러스터 업데이트

②를 건너뛰고 AccountingStorageEnforce=associations가 적용되면 등록되지 않은 사용자는 어떤 파티션에도 제출할 수 없습니다. "갑자기 제출이 안 된다"는 신고의 첫 번째 확인 항목입니다: sacctmgr show assoc user=<name>.

7-1. 두 계층의 역할 — 파티션만으로는 독점을 막을 수 없습니다

 Slurm PartitionSlurm Accounting (QoS)
제어 단위파티션사용자 / 계정 / QoS
가능한 제약최대 실행시간(MaxTime), 최대 노드수, 파티션 우선순위, preemption사용자별 동시 실행/제출 수, 팀별 GPU·CPU·메모리 총량(GrpTRES)
강제력Slurm 기본 동작 (권고 수준)AccountingStorageEnforce로 강제
역할자원 배분의 실제로 강제하고 기록하는 시스템

7-2. slurm-extra.conf (S3에 업로드)

# ---- 자원 할당 단위 ----
# 멀티스레딩 활성(기본) 기준: 192 vCPU / 8 GPU = 24
# DisableSimultaneousMultithreading을 켰다면 96/8 = 12로 조정
DefCPUPerGPU=24
DefMemPerGPU=480000

# ---- 스케줄링 / 우선순위 ----
SchedulerType=sched/backfill
PriorityType=priority/multifactor
PriorityWeightPartition=100000
PriorityWeightQOS=1000
PriorityWeightFairshare=100         # 1단계는 파티션/QoS 우선순위 중심. fair-share를 실제로 쓰려면 Partition과 같은 자릿수로

# ---- Preemption ----
PreemptType=preempt/partition_prio
PreemptMode=REQUEUE

# ---- 내결함성 ----
JobRequeue=1
KillWait=300                    # 시간 초과 시 SIGTERM → SIGKILL 간격 (기본 30초). 체크포인트 저장 여유
# UnkillableStepTimeout은 SIGKILL 이후 "죽지 않는 프로세스" 판정 대기시간 — 체크포인트와 무관, 기본값 유지

# ---- Health check (Step 8) — ⚠ 반드시 로컬 디스크 경로. /fsx에 두면 Lustre 장애 = 전 노드 drain·교체 ----
HealthCheckProgram=/opt/ops/health/periodic-check.sh
HealthCheckInterval=300
HealthCheckNodeState=IDLE
Prolog=/opt/ops/health/prolog-gpu-quick.sh
Epilog=/opt/ops/health/epilog-on-failure.sh

# ---- Accounting ----
AccountingStorageTRES=cpu,mem,node,billing,gres/gpu
AccountingStorageEnforce=limits,qos,associations

# ---- 파티션 (노드 이름 규칙: <queue>-st-<computeresource>-<n>) ----
# ⚠ 존재하지 않는 노드를 참조하면 slurmctld가 기동하지 않습니다. 단계별로 Nodes= 범위를 맞추십시오.
#    2노드 검증 : 네 파티션 모두 gpu-st-b300-[1-2]
#    16노드 파일럿: 아래 값
#    125노드    : [1-125] 등으로 갱신 (Step 10)
# GraceTime = 선점(REQUEUE)당할 때 SIGTERM 후 유예 시간(초) — 체크포인트 저장용
PartitionName=debug     Nodes=gpu-st-b300-[1-2]   Priority=100   MaxTime=00:30:00    Default=NO  State=UP AllowQOS=debug_qos     GraceTime=120
PartitionName=normal    Nodes=gpu-st-b300-[1-8]   Priority=200   MaxTime=1-00:00:00  Default=YES State=UP AllowQOS=normal_qos    GraceTime=600
PartitionName=large     Nodes=gpu-st-b300-[1-16]  Priority=300   MaxTime=7-00:00:00  Default=NO  State=UP AllowQOS=large_qos     GraceTime=600
PartitionName=exclusive Nodes=gpu-st-b300-[1-16]  Priority=1000  MaxTime=14-00:00:00 Default=NO  State=UP PreemptMode=REQUEUE AllowQOS=exclusive_qos
함정 · UnkillableStepTimeout은 체크포인트용 파라미터가 아닙니다

공개 예제(KAIT 블로그 포함)에 UnkillableStepTimeout=300이 "종료 전 체크포인트 시간 확보"로 소개되어 있으나 이는 오해입니다. 이 값은 SIGKILL을 보낸 뒤에도 죽지 않는 프로세스를 이상으로 판정하기까지의 대기시간이고, 학습 프로세스에 저장 기회를 주지 않습니다.

체크포인트 여유를 만드는 조합은 세 가지입니다: KillWait(시간 초과 시 SIGTERM→SIGKILL 간격), ② 파티션/QoS GraceTime(선점 시 유예), ③ 사용자 측 sbatch --signal=B:USR1@600(종료 600초 전 시그널 수신 후 저장). ③이 없으면 ①②는 시간만 벌 뿐 저장은 일어나지 않습니다.

함정 · 확장할 때 Nodes= 범위를 잊지 마십시오

파티션의 Nodes=는 노드 이름을 하드코딩합니다. 16노드 → 125노드로 확장하면 이 범위와 팀별 GrpTRES 쿼터를 함께 갱신해야 합니다. 안 하면 새 노드가 어느 파티션에도 속하지 않아 유휴 상태로 과금됩니다.

7-3. 계정과 QoS 생성 (head node에서)

# 팀 계정
sacctmgr --immediate add account team-a Description="Team A"
sacctmgr --immediate add account team-b Description="Team B"

# 사용자 등록 (OS 계정이 먼저 존재해야 함)
sacctmgr --immediate add user name=${USER} account=team-a

# QoS 생성 및 제한 (여러 개는 name=a,b,c 형식)
sacctmgr --immediate add qos name=debug_qos,normal_qos,large_qos,exclusive_qos
sacctmgr -i modify qos debug_qos     set MaxJobsPerUser=1 MaxSubmitJobsPerUser=2 Priority=1000
sacctmgr -i modify qos normal_qos    set MaxJobsPerUser=4 MaxSubmitJobsPerUser=8 Priority=2000
sacctmgr -i modify qos large_qos     set Priority=3000
sacctmgr -i modify qos exclusive_qos set MaxJobsPerUser=1 MaxSubmitJobsPerUser=2 Priority=10000

# ★ 팀별 GPU 총량 상한 — 독점 방지의 핵심
sacctmgr -i modify account team-a set GrpTRES=gres/gpu=64
sacctmgr -i modify account team-b set GrpTRES=gres/gpu=64

# 계정별 사용 가능 QoS와 기본값 (모든 팀 계정에 반복)
sacctmgr -i modify account team-a set qos+=debug_qos,normal_qos,large_qos DefaultQOS=normal_qos
sacctmgr -i modify account team-b set qos+=debug_qos,normal_qos,large_qos DefaultQOS=normal_qos
# exclusive_qos는 필요한 팀에만 별도 부여

# 확인
sacctmgr show assoc format=account,user,qos,defaultqos,grptres
scontrol show partition | grep -E 'PartitionName|Default|AllowQos'   # 기본 파티션이 normal인지, gpu가 Hidden인지
팁 · 실제로 막는 것은 이 두 줄입니다

GrpTRES=gres/gpu=N + AccountingStorageEnforce=limits. 이 조합이 있어야 팀이 배정량을 넘겨 제출할 때 실제로 거부됩니다. 둘 중 하나만 있으면 제한이 기록만 되고 강제되지 않습니다.

함정 · 리포팅 명령 2가지 주의
  • sacct --state=...-E now를 명시하지 않으면 조용히 빈 결과를 반환합니다.
  • sreport는 시간별 롤업을 따라가므로 최신 데이터가 반영되지 않습니다. 실시간 조회는 sacct를 쓰십시오.
STEP 8

GPU 헬스체크와 복원력 설계

D+1

내장 체크를 끈 대신 직접 구성합니다. 1,000 GPU가 며칠씩 도는 환경에서 이 단계는 선택이 아닙니다.

8-1. 3단계 배치 (AWS 문서 권고 모델)

시점어디에무엇을허용 시간
노드 기동 시 CustomActions/
OnNodeConfigured
job이 아직 없으므로 깊은 dcgmi diag(level 2~3) + EFA 열거 확인 + 토폴로지 검증 수 분 허용
job 시작 전 Slurm prolog nvidia-smi + 커널로그 Xid 에러 스캔, 또는 dcgmi diag -r 1 수 초 이내
job 종료 후 Slurm epilog job이 실패했을 때만 level-2 진단 → 다음 job 전에 열화 GPU 격리 깊게
왜 3단계인가

기동 시 체크는 시작 시점의 결함만 잡습니다. 실행 중 발생하는 열화는 못 잡습니다. 그래서 prolog(빠른 게이트)와 epilog(실패 시 심층)를 함께 두어 시간축을 덮습니다.

8-2. 이것이 자동 교체로 연결됩니다 — 핵심

AWS 문서 원문입니다.

AWS ParallelCluster replaces drained or failed static nodes (and terminates dynamic ones), so draining a node with a confirmed fault results in it being replaced.
헬스체크가 결함 확정 │ ▼ scontrol update NodeName=<n> State=DRAIN │ ▼ ParallelCluster(clustermgtd)가 static 노드를 자동 교체 │ ▼ 새 노드가 OnNodeConfigured 심층 진단 통과 │ ▼ 큐에 복귀 → job requeue 후 체크포인트에서 재개
함정 · static 노드만 교체됩니다

MinCount == MaxCount(전량 static)여야 교체됩니다. dynamic 노드는 종료만 되고 교체되지 않습니다. 앞서 전량 static을 권장한 실질적 이유가 이것입니다.

함정 · 이 설계의 뒷면 — 오탐 하나가 노드 교체 하나입니다

"DRAIN = 자동 교체"는 결함 노드에는 축복이지만, 헬스체크 스크립트가 잘못 실패하면 정상 노드가 인스턴스째 교체됩니다. 특히 prolog는 실패하면 Slurm이 그 노드를 DRAIN하므로, prolog 자체의 장애 원인이 곧 교체 원인이 됩니다.

  • prolog / epilog / HealthCheckProgram은 로컬 디스크(/opt/ops/health)에서 실행하십시오. /fsx에 두면 Lustre가 잠깐 마운트를 잃는 순간 모든 노드의 prolog가 동시에 실패 → 전 노드 DRAIN → 전 노드 교체가 일어납니다. 스크립트는 compute-start.sh에서 S3 → 로컬로 복사합니다(Step 3).
  • prolog는 GPU·EFA 결함 이외의 실패(스토리지 마운트, 네트워크 지연)에는 exit 0으로 끝내고 로그만 남기십시오. 스토리지 장애는 노드 교체로 해결되지 않습니다.
  • 수동 점검·정비에는 DRAIN이 아니라 maintenance reservation을 쓰십시오(Step 10). DRAIN은 교체 명령입니다.

8-3. job 내결함성

  • JobRequeue=1 + sbatch --requeue로 제출
  • KillWait=300(시간 초과) + 파티션 GraceTime=600(선점) — SIGTERM 뒤 SIGKILL까지의 여유 시간
  • 학습 스크립트는 sbatch --signal=B:USR1@600으로 종료 600초 전 시그널을 받아 체크포인트를 저장하고 스스로 종료
함정 · 체크포인트는 직접 만들어야 합니다

ParallelCluster가 체크포인트를 자동 생성해 주지는 않습니다. 저장과 재개 로직은 학습 스크립트의 책임입니다. requeue는 "job을 다시 실행"할 뿐이므로, 재개 지점이 없으면 처음부터 다시 돕니다.

8-4. pcluster-diag

ParallelCluster 3.16.0부터 공식 AMI에 진단 도구 pcluster-diag가 포함됩니다. 노드에서 온디맨드로 실행할 수 있습니다. 장애 조사 시 가장 먼저 돌려보십시오.

8-5. 스크립트 골격

동작 원리를 보이기 위한 최소 골격입니다. 실제 판정 기준(Xid 코드 목록, 허용 온도, 재시도 횟수)은 2노드 검증에서 실측 후 확정하십시오. 네 파일 모두 compute-start.sh가 S3에서 /opt/ops/health/로 복사합니다.

# compute-start.sh (OnNodeStart) — 헬스체크 스크립트 로컬 복사 + needrestart 가드
#!/bin/bash
set -euo pipefail
mkdir -p /opt/ops/health
aws s3 sync s3://${SCRIPT_BUCKET}/health/ /opt/ops/health/ --region ap-northeast-2
chmod 755 /opt/ops/health/*.sh
if [ -d /etc/needrestart ]; then
  mkdir -p /etc/needrestart/conf.d
  echo '$nrconf{override_rc}{qr(^slurmd)} = 0;' > /etc/needrestart/conf.d/90-slurm.conf
fi
# prolog-gpu-quick.sh — 수 초 이내. GPU/EFA 결함만 실패(exit 1)로 처리
#!/bin/bash
LOG=/var/log/ops-prolog.log
fail(){ echo "$(date -Is) job=$SLURM_JOB_ID FAIL: $*" >> $LOG
        scontrol update NodeName=$(hostname -s) State=DRAIN Reason="prolog: $*"; exit 1; }
timeout 10 nvidia-smi --query-gpu=count --format=csv,noheader >/dev/null 2>&1 || fail "nvidia-smi"
n=$(nvidia-smi -L 2>/dev/null | wc -l); [ "$n" -eq 8 ] || fail "gpu count $n"
# 최근 부팅 이후 치명 Xid (79 fallen off bus, 74 NVLink, 48 DBE, 63/64 row remap)
if journalctl -k -b --no-pager | grep -E 'NVRM: Xid .*: (79|74|48|63|64),' -q; then fail "xid"; fi
efa=$(ls /sys/class/infiniband/ 2>/dev/null | wc -l); [ "$efa" -eq 16 ] || fail "efa devices $efa"
exit 0    # 스토리지·네트워크 등 그 외 문제는 로그만 남기고 통과
# epilog-on-failure.sh — job이 실패했을 때만 level-2 진단 (노드에 다른 job이 없을 때만)
#!/bin/bash
[ "${SLURM_JOB_EXIT_CODE:-0}" = "0" ] && exit 0
running=$(squeue -h -w $(hostname -s) -t RUNNING | wc -l)
[ "$running" -gt 0 ] && exit 0            # 공유 노드에서 dcgmi diag 금지
if ! timeout 900 dcgmi diag -r 2 > /var/log/ops-epilog-diag.$SLURM_JOB_ID.log 2>&1; then
  scontrol update NodeName=$(hostname -s) State=DRAIN Reason="epilog: dcgmi diag -r 2 failed job=$SLURM_JOB_ID"
fi
exit 0
# periodic-check.sh (HealthCheckProgram, IDLE 노드에서 5분마다) — 가볍게
#!/bin/bash
nvidia-smi --query-gpu=temperature.gpu,ecc.errors.uncorrected.volatile.total --format=csv,noheader 2>/dev/null  | awk -F, '{ if ($1+0 > 90 || $2+0 > 0) bad=1 } END { exit bad }'  || scontrol update NodeName=$(hostname -s) State=DRAIN Reason="periodic: temp/ecc"
exit 0
# gpu-healthcheck-startup.sh (OnNodeConfigured) — job 없음, 수 분 허용
#!/bin/bash
set -e
nvidia-smi topo -m > /var/log/ops-topo.log
[ $(ls /sys/class/infiniband/ | wc -l) -eq 16 ]
timeout 1800 dcgmi diag -r 3 > /var/log/ops-startup-diag.log     # 실패 시 exit≠0 → 노드가 큐에 들어오지 않음
STEP 9

검증 — 2노드에서 전부 통과시킬 항목

D+2 ~ D+5

9-1. 인프라 기본

sinfo -N -l
scontrol show nodes | grep -E 'NodeName|State|CfgTRES|Gres'

# 파티션 — 기본 파티션이 normal이고 gpu가 Hidden/root 전용인지
scontrol show partition | grep -E 'PartitionName|Default|Hidden|AllowGroups|AllowQos'

# GPU 인식 — 8개, gres/gpu=8
srun -p normal -N1 --gres=gpu:8 nvidia-smi

# EFA 열거 — 16 도메인이어야 함
srun -p normal -N1 fi_info -p efa | grep -c domain
srun -p normal -N1 ls /sys/class/infiniband/

# 스토리지
df -h /fsx /home
lfs df -h /fsx

9-2. NCCL 다중 노드 — 가장 중요한 성능 검증

# 컨테이너 이미지 (태그 고정). enroot는 '#' 레지스트리 구분자를 씁니다
enroot import -o /fsx/nccl-tests.sqsh \
  "docker://public.ecr.aws#hpc-cloud/nccl-tests:<tag>"

# 2노드 / 16 GPU all_reduce
srun -p normal -N2 --ntasks-per-node=8 --gres=gpu:8 \
  --container-image=/fsx/nccl-tests.sqsh \
  all_reduce_perf -b 8 -e 16G -f 2 -g 1

합격 기준

  • 로그에 NET/OFI Selected provider is efafound 16 nics
  • # Out of bounds values : 0 / OK
  • busbw가 메시지 크기에 따라 증가하고 대형 메시지에서 포화
함정 · nics 개수가 16이 아니면 NIC 구성 오류입니다

found 16 nics가 아니라 1이나 8로 나오면 EFA 인터페이스가 제대로 붙지 않은 것입니다. 이 상태로도 job은 돌지만 대역폭이 몇 분의 일로 떨어집니다. 성능이 안 나온다는 신고의 가장 흔한 원인이므로, 이 로그 한 줄을 반드시 확인하십시오.

주의 · p6-b300의 공개 기준 대역폭 수치가 없습니다

참고로 p6-b200 4노드 all_reduce에서 377 GB/s가 관측된 사례가 있습니다. p6-b300의 공개 기준치는 확인하지 못했습니다 확인 필요. 자사 실측값을 기준선으로 기록하고, 이후 노드 교체·확장 시 회귀 판정에 쓰십시오.

9-3. 스토리지 성능

  • Lustre 튜닝 적용 전/후 순차 쓰기 처리량 비교
  • 실제 체크포인트 저장 1회 소요시간 측정 → Capacity Block 종료 시각 계획에 사용(Step 0)
  • 로컬 NVMe 캐시 적용 시 데이터 로딩 시간 변화
  • ENA 350 Gbps가 병목인지 판정 → 레이아웃 (B) 전환 여부 결정

9-4. 장애 리허설 필수

시나리오확인할 것
OnNodeConfigured 심층 진단정상 노드는 통과, 결함 주입 시 노드가 큐에 들어오지 않음
prolog 빠른 체크job 시작 지연이 수 초 이내
노드 강제 종료job requeue → 체크포인트 재개까지 MTTR 측정
scontrol update State=DRAINParallelCluster가 static 노드를 자동 교체하는지 확인
epilogjob 실패 시 심층 진단이 돌고 결함 노드가 격리되는지
팁 · 이 리허설의 목적은 MTTR 수치입니다

며칠짜리 학습에서 노드 하나가 죽었을 때 몇 분 만에 복구되는지를 숫자로 알아야 운영 계획과 SLA를 세울 수 있습니다. 감으로 넘기지 말고 측정해서 기록하십시오. 나중에 다른 플랫폼과 비교할 때도 이 값이 근거가 됩니다.

9-5. 멀티유저

  • GrpTRES=gres/gpu=N 초과 제출이 실제로 거부되는지
  • MaxJobsPerUser 초과 제출이 막히는지
  • 낮은 우선순위 파티션 job이 높은 우선순위 job에 의해 실제로 preempt(requeue) 되는지
  • sacct -a -S <date> -E now 로 사용자별 집계가 나오는지
  • 일반 사용자가 -p gpu로 제출하면 거부되는지 (QoS 우회 차단 확인)
  • --signal=B:USR1@600을 쓴 job이 scancel·선점 시 실제로 체크포인트를 남기는지
STEP 10

확장 — 2 → 16 → 125노드

D+7 이후
# MinCount/MaxCount만 올리고 업데이트
pcluster update-cluster -n llm-poc -c cluster-config.yaml
변경 내용fleet 정지 필요?
MinCount / MaxCount 증가불필요
추가, compute resource 추가불필요
MinCount / MaxCount 감소필요 — 또는 QueueUpdateStrategy: TERMINATE (3.9.0+)
삭제, compute resource 삭제필요 — 해당 노드가 전부 종료됨
함정 · 축소 시 job이 사라질 수 있습니다

노드가 제거되면 그 노드의 sbatch job은 requeue되지만, 조건을 만족하는 다른 노드가 없으면 NODE_FAIL로 큐에서 사라져 수동 재제출이 필요합니다.

축소나 노드 교체를 계획했다면 대상 노드에 미리 정비 예약을 걸어 새 job이 들어가지 않게 하십시오.

scontrol create reservation ReservationName=maint_for_update user=root \
  starttime=now duration=infinite flags=maint,ignore_jobs \
  nodes=gpu-st-b300-[15-16]

# 작업 후 해제
scontrol delete ReservationName=maint_for_update

이미 실행 중인 job에는 영향이 없습니다.

확장 시 함께 갱신할 항목 체크리스트
  • Head node 사양 재검토 — 125노드는 16노드와 스케일링 오케스트레이션 부하가 다릅니다
  • 파티션 Nodes= 범위 — 새 노드가 어느 파티션에도 안 속하면 유휴 과금. 먼저 MinCount를 올려 노드가 존재하게 만든 뒤 include 파일을 갱신하십시오(반대 순서면 slurmctld 기동 실패)
  • 팀별 GrpTRES 쿼터 — 총량이 늘었으니 재배분
  • FSx 용량·처리량 — 노드 수에 비례해 스토리지 부하 증가
  • 서브넷 IP 여유 — 레이아웃 (B)로 전환했다면 특히 확인
  • Capacity Block 경로면 compute resource 추가 — 블록당 64대 한도

운영 상시 주의사항

1. 마이너 버전 업그레이드는 클러스터 재생성입니다

3.16 → 3.17로 갈 때 클러스터를 다시 만들어야 합니다. Step 2에서 FSx를 외부에 만들었다면 다음 절차로 무중단에 가깝게 이관됩니다.

  1. 새 버전 CLI로 새 클러스터 병렬 생성 → 같은 파일시스템 연결
  2. 데이터·애플리케이션 검증
  3. 검증 완료 후 기존 클러스터만 삭제
2. Head node 장애 시 무엇이 멈추는가

실행 중 job은 계속 돕니다. 멈추는 것은 신규 job 제출, 스케줄러 명령, 노드 스케일링, 장애 노드 자동 교체입니다. 즉 복원력 기능 자체가 head node에 의존합니다. 알람을 걸고, 사양을 여유 있게 두십시오.

3. Capacity Block 만료 관리

KST 20:00부터 노드가 종료되기 시작합니다. 만료 전 새 블록을 예약하고 compute resource의 CapacityReservationId를 갱신하십시오. 블록은 취소·이동·분할이 불가능하고 연장(extend)만 됩니다.

4. 그 밖에 기억할 것
  • 커스텀 AMI를 만들었다면 ParallelCluster 릴리스마다 다시 만들어야 합니다. CustomActions로 해결 가능한 것은 그쪽으로 두십시오.
  • NFSv3 외부 서버를 마운트한다면 lockd 포트가 3.16.0부터 32768 → 4045로 바뀌었습니다. 방화벽에서 TCP/UDP 4045를 열지 않으면 마운트가 실패합니다.
  • MIG를 쓴다면 3.16.0부터 GPU health check가 DCGM 진단을 건너뜁니다(dcgmi diag가 MIG 미지원). B300을 MIG로 쪼개는 것은 학습용으로 비경제적이므로, 필요하면 추론·개발용 별도 큐로 분리하십시오.
  • ptrace 보호 — Ubuntu 기본 활성이고 libfabric 동작에 영향을 줍니다. ParallelCluster가 비활성화하지만 커스텀 AMI를 쓰면 직접 확인하십시오.

비용 라인아이템

ParallelCluster는 도구 자체가 무료입니다. 청구되는 것은 사용한 AWS 리소스뿐입니다.

라인아이템비고
GPU 컴퓨트 (p6-b300.48xlarge)서울 On-Demand $209.1735/시간 (2026-09-14, Linux). 비용의 대부분
Head node / Login nodes상시 실행
FSx for Lustre용량 × 처리량 등급. 무시할 수 없는 금액
FSx for OpenZFS / EFS/home
Aurora MySQLaccounting 사용 시
NAT Gateway데이터 처리량 과금 — S3/ECR VPC 엔드포인트로 절감
CloudWatch Logs / AMP / AMG관측
S3데이터셋 · 체크포인트 아카이브
팁 · 최대 낭비 요인은 유휴 GPU입니다

시간당 $209짜리 노드가 유휴로 도는 것이 가장 큰 낭비입니다. AWS Budgets 예산·알람과 CloudWatch 청구 알람을 걸고, Step 7의 팀별 GrpTRES 쿼터와 파티션 설계로 활용률을 관리하십시오. Capacity Block / Savings Plans로 단가도 함께 낮추십시오.

참고자료

필수 문서 (docs.aws.amazon.com/parallelcluster/latest/ug/)

주제경로
EFA 기본 · 자동 구성efa-v3.html
p6-b300 NIC 커스터마이징 (전체 예제)tutorial-network-customization-v3.html
GPU health check 권고 (p6 계열 주의)best-practices-v3.html
Capacity Blocklaunch-instances-capacity-blocks.html
ODCRlaunch-instances-odcr-v3.html
클러스터 용량 · 노드 라이프사이클slurm-cluster-capacity-size-and-update.html
Slurm 설정 커스터마이징slurm-configuration-settings-v3.html
Slurm prolog / epilogslurm-prolog-epilog-v3.html
Slurm accountingslurm-accounting-v3.html
부트스트랩 커스텀 액션custom-bootstrap-actions-v3.html
Login nodesLoginNodes-v3.html
설정 파일 전체 레퍼런스cluster-configuration-file-v3.html
알려진 이슈github.com/aws/aws-parallelcluster/wiki

국내 대규모 사례 꼭 보십시오

AWS HPC Blog · Part 1: Managing Large-Scale LLM Training with AWS ParallelCluster (2026-08)
  • 한국 정부 국가 AI 사업 KAIT "AI for Research"30 × p5en.48xlarge (240 H200), 8개월
  • KAIST · GIST · 서울대병원 · 서울대 · 한양대 · 성균관대 · 고려대
  • 실제 구성: 최대 16 × p5en + FSx for Lustre 230.4 TiB, S3 동기화, CloudWatch → SNS → Lambda → Slack
  • cluster-config.yaml / slurm-settings.conf 전문과 sacctmgr 명령까지 공개
  • Part 2: FSx for Lustre 세팅, instance store 캐싱, OOM 처리, 정비 절차, 이벤트 모니터링

이 문서의 Step 5·7 기준 설정도 여기서 검증된 패턴을 반영했습니다. 다만 그 글의 IAM 구성(head/compute에 AdministratorAccess)은 따라 하지 마십시오.

도구 · 벤치마크

미확정 · AWS 확인 필요 항목

#항목영향언제
1서울에서 p6-b300 가용 AZ서브넷 · FSx · placement group 배치가 전부 종속착수 전 필수
2서울 p6-b300 Capacity Block 최대 블록 크기 (64대인지 그 이하인지)125노드를 몇 개 compute resource로 나눌지 결정착수 전
3p6-b300 다중 노드 NCCL 기대 대역폭 기준치성능 합격 판정 기준. 공개 수치 없음 → 자사 실측 필요Step 9
4p6-b300에서 FSx Lustre over EFA / GPUDirect Storage 지원 여부스토리지 대역폭 설계Step 2 이후
53.16.1에서 needrestartslurmd 재시작 방어 여부장기 job 안정성Step 3
6EC2 P 인스턴스 vCPU 쿼터 증설 리드타임일정의 첫 의존성 (ODCR 경로만)Step 0
7착수 시점의 ParallelCluster 최신 안정 릴리스 (3.17.0 릴리스 여부)한 단계 뒤 버전으로 시작하면 곧 재생성 필요착수 전
8Capacity Block 합계 256대 한도의 적용 단위 (계정 vs 조직)다른 팀·계정의 CB와 합산되는지Step 0