AWS PCS 구축 가이드
서울 리전 · p6-b300 · 대규모 LLM 학습 환경
Part 1을 먼저 읽으십시오. 특히 §4 되돌리기 어려운 결정 7가지는 클러스터를 만든 뒤 바꾸면 재생성이나 대규모 재작업이 필요한 항목입니다. Part 2는 순서대로 따라가는 절차이고, 각 단계 안에 그 단계에서 실제로 부딪히는 함정과 팁을 배치했습니다. 건너뛰지 말고 단계 내 경고 박스를 읽어주십시오.
AWS ParallelCluster와 다른 점은 곳곳에 PCS 차이로 표시했습니다. ParallelCluster 경험이 있는 분이 그 감각으로 PCS를 다루다 빠지는 함정이 이 표시 뒤에 있습니다.
1. 무엇을 만드는가
AWS PCS(Parallel Computing Service)는 Slurm 컨트롤러(slurmctld)와 accounting DB(slurmdbd)를 AWS가 관리형으로 운영하고, 컴퓨트 노드는 고객 계정의 EC2로 띄우는 서비스입니다. ParallelCluster처럼 "설정 파일 하나로 CloudFormation을 찍어내는 도구"가 아니라, 클러스터·노드그룹·큐라는 AWS 리소스를 API로 만드는 서비스입니다. 서비스 요금이 있지만 이 규모에서는 GPU 비용의 약 0.4%입니다(비용).
2. 구성요소 개념
PCS의 리소스 계층은 세 단계입니다. Slurm 용어와의 매핑을 정확히 알아야 API 인자가 읽힙니다.
slurmctld(+ 선택 slurmdbd). 사이즈(Small/Medium/Large)와 Slurm 메이저 버전을 가집니다. 사이즈는 생성 후 변경 불가, 버전은 UpdateCluster로 in-place 업그레이드 가능. 고객은 slurm.conf·slurmdbd.conf를 직접 편집하지 않고 허용 목록(allow-list) 파라미터만 넣습니다.(CNG)
min/max · 구매옵션(ONDEMAND/SPOT/CAPACITY_BLOCK) · AMI · IAM instance profile · node lifecycle actions를 정합니다. 기본 한도 클러스터당 10개.(= Slurm partition)
AllowQos, MaxTime, GraceTime 등)은 여기서 넣습니다. 기본 한도 클러스터당 10개. PCS 차이 PCS가 임의로 만드는 파티션은 없습니다. 큐를 만든 것만 파티션입니다.min == max. 항상 켜져 있고 PCS가 수량을 유지합니다. 대규모 학습과 Capacity Block에서는 이 모드가 기본입니다.min = 0(dynamic) 또는 0 < min < max(mixed, Slurm 24.05+). job에 따라 뜨고 지며 scaleDownIdleTime 뒤 종료. 125노드 단일 job을 dynamic으로 던지면 용량 확보 실패 → 반납 → 재시도 루프에 빠질 수 있습니다(Step 0).PCS 문서 원문: job은 전체 노드가 확보되기 전에는 시작하지 않고, 큰 job은 부분씩 확보하다가 전체를 못 채우면 이미 launch한 인스턴스를 반납할 수 있습니다. 그 사이 인스턴스는 과금됩니다. 같은 문서가 대안을 명시합니다: "back the compute node group with a capacity reservation."
→ ODCR 또는 Capacity Block + static CNG(min = max)가 1,000 GPU 학습의 전제입니다. Capacity Block은 예약 창 전체가 과금되므로 0에서 스케일업하게 두면 유휴 시간만큼 낭비입니다.
3. p6-b300 하드웨어 특성 — PCS 관점
| 항목 | 값 | 설계에 미치는 영향 |
|---|---|---|
| GPU | 8 × NVIDIA B300, HBM 합계 2.1 TB | 노드 내 8 GPU가 NVLink 도메인. TP는 노드 내, PP/DP는 노드 간(EFA) |
| vCPU | 192 → PCS에서는 96 CPU | PCS 차이 PCS는 부트스트랩에서 SMT를 강제 비활성합니다(설정 불가). Slurm에는 96 물리코어로 등록 → GPU당 12 CPU 기준으로 --cpus-per-task, DataLoader(num_workers)를 설계 |
| 메모리 | 4,096 GiB | DefMemPerCPU≈40000(MB, 96 CPU 기준). DefMemPerGPU는 PCS 허용 목록에 없음 |
| 로컬 NVMe | 8 × 3,840 GB | Enroot 오버레이 + 데이터 캐시. lifecycle action에서 RAID/마운트(EVERY_BOOT) |
| 네트워크 카드 | 17장 — card 0은 ENA 전용(EFA 미지원, 최대 350 Gbps), card 1–16은 EFA 각 최대 400 Gbps | PCS 차이 PCS는 EFA를 자동 구성하지 않습니다. launch template에 17개 인터페이스를 직접 정의(Step 5). P5/P6-B200과 배선 규칙이 다릅니다(card 0 = ENA-only, EFA는 card 1–16의 DeviceIndex 0) |
| 노드당 사설 IP | 17개 | PCS 차이 PCS 레퍼런스는 InterfaceType: efa(efa-only 아님)를 요구 → 인터페이스마다 IP 소비. 125노드 = 2,125 IP → 서브넷 /20. efa-only 동작 여부는 PoC 실측 확인 필요 |
| EFA 총 대역폭 | 6,400 Gbps | NCCL 노드 간 통신. 다중 NIC 인스턴스라 퍼블릭 IP 자동 할당 불가 → 프라이빗 서브넷 + NAT |
| On-Demand 단가 (서울) | $209.1735 / 시간 | 비용의 대부분. 2026-09-14 기준, Linux |
4. 되돌리기 어려운 결정 7가지
아래 항목은 클러스터를 만든 뒤 바꾸면 클러스터 재생성, 또는 launch template·CNG·서브넷을 전부 다시 만드는 재작업이 필요합니다. 구축을 시작하기 전에 확정하십시오.
| # | 결정 항목 | 왜 되돌리기 어렵나 | 권장 |
|---|---|---|---|
| 1 | 클러스터 사이즈 변경불가 | PCS 문서: "You can't change the cluster size after you create the cluster." login CNG도 관리 인스턴스 수에 포함 | Medium (≤512 인스턴스, ≤8,192 job). 2노드 PoC라도 Medium으로 시작해야 125노드까지 한 클러스터로 갑니다. Small(≤32)은 GPU 32대 + login 2대에서 이미 초과 |
| 2 | Availability Zone 변경불가 | GPU CNG는 단일 서브넷(=단일 AZ)이어야 EFA가 동작. 서브넷·FSx·placement group이 모두 여기에 묶임 | 서울에서 p6-b300이 실제 제공되는 AZ를 먼저 조회(Step 0) |
| 3 | GPU 서브넷 CIDR 확장불가 | 서브넷은 생성 후 크기를 늘릴 수 없고, PCS 경로는 노드당 17 IP를 소비 | /20 이상 (125노드 × 17 = 2,125 IP). login·FSx·NAT는 별도 서브넷(Step 1) |
| 4 | Slurm 메이저 버전 | in-place 업그레이드는 가능하나, SPANK 플러그인을 쓰면 25.11 이하에서 rolling 업그레이드 불가. 25.11은 GPU affinity용 Sockets를 CNG마다 직접 넣어야 함 |
26.05(PCS 출시 2026-09-10, EOL 2027-11-30). GPU affinity 자동, SPANK 제약 해소. 보수적으로 가려면 25.11(EOL 2027-05-31). 25.05는 2026-11-30 EOL이라 대상 아님 |
| 5 | 용량 확보 경로 Capacity Block vs ODCR |
launch template 구조(MarketType, CapacityReservationTarget, placement group 유무)와 CNG 분할 수가 달라짐 |
Step 0 · Step 5. Capacity Block은 CNG당 블록 1개라 125노드 = 최소 2 CNG |
| 6 | 공유 스토리지를 클러스터 외부에 생성 치명적 |
awslabs 레퍼런스처럼 nested stack 안에서 FSx를 만들면 스택 삭제 시 데이터가 함께 삭제됩니다. 클러스터 사이즈 변경(#1) 등으로 재생성할 때 그대로 사고가 됩니다 | FSx를 별도 스택으로 만들고 ID로 참조. lifecycle action에서 마운트(Step 2) |
| 7 | AMI 전략 | PCS-ready DLAMI를 SSM /latest/로 참조하면 stack update마다 AMI가 조용히 바뀝니다(drift). Enroot/Pyxis를 첫 부팅에 설치하면 노드마다 부팅 8–12분 |
PoC: PCS-ready DLAMI를 ID로 pin. 본운영: Enroot/Pyxis pre-bake 커스텀 AMI(부팅 ~3분). 릴리스 SNS 구독(Step 3) |
클러스터 사이즈를 Small로 시작하면 32노드에서 벽에 부딪혀 클러스터를 새로 만들어야 합니다. 그때 FSx가 클러스터 스택 안에 있으면 학습 데이터와 체크포인트가 사라집니다. 두 결정은 서로 얽혀 있습니다: 처음부터 Medium + 외부 스토리지로 시작하면 재생성 자체가 거의 필요 없어집니다.
PCS는 ParallelCluster와 달리 Slurm 버전 업그레이드에 클러스터 재생성이 필요하지 않습니다(Step 10). 재생성 사유는 사실상 사이즈 변경 하나입니다.
5. 설계 요약
| 영역 | 결정 | 근거 / 상세 |
|---|---|---|
| 클러스터 | Medium · Slurm 26.05 · accounting STANDARD | 사이즈 변경 불가. 26.05는 GPU affinity 자동·SPANK rolling 제약 해소. accounting은 사후 on/off 가능하나 멀티팀 확정이면 처음부터 |
| AMI | PCS-ready DLAMI (ID pin) → 본운영 pre-bake | NVIDIA 드라이버·CUDA·EFA·Lustre 클라이언트·PCS Agent·Slurm 내장. Enroot/Pyxis는 미포함 → lifecycle action 또는 Image Builder(Step 3) |
| EFA | launch template에 17 NIC 수기 정의, InterfaceType: efa | PCS 차이 자동 구성 없음. awslabs add-cng-p6-b300.yaml이 완성된 배선(Step 5) |
| 네트워크 | GPU 서브넷 프라이빗 /20 + NAT, 단일 AZ | 17 IP/노드. 다중 NIC은 퍼블릭 IP 자동 할당 불가 |
| 노드 구성 | GPU CNG 전량 static, 예약 기반 | job-level scaling의 확보 실패 루프 회피. Capacity Block은 CNG당 1블록 |
| GPU 헬스체크 | 관리형 기능 없음 → 직접 구성 (lifecycle action + HealthCheckProgram + prolog/epilog) | PCS 차이 HyperPod의 auto-healing에 해당하는 기능이 PCS에는 없습니다. awslabs 스위트로 구현(Step 8) |
| 스토리지 | /fsx Lustre + /home OpenZFS + 로컬 NVMe + S3 | 외부 생성 후 ID 참조. 마운트는 nodeBootstrapped 스테이지, onError: TERMINATE |
| 멀티팀 | 큐(≤10) + Slurm accounting QoS | GrpTRES=gres/gpu=N이 실제 강제 수단. QoS가 DB에 없는 상태로 큐에 AllowQos를 넣으면 25.11+에서 slurmctld가 fatal(Step 7) |
| 관측 | AMP/AMG 관리형 + ADOT Collector | AWS 공식 observability_for_pcs 레시피. B300은 DCGM 4.5.2 이상 필요 |
| 확장 | 2 → 16 → 최대 125노드 | UpdateComputeNodeGroup으로 min/max 조정, CNG 추가는 큐에 매핑만(Step 10) |
Part 2 · 구축 절차
용량과 쿼터 확보
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가 이후 GPU 서브넷·FSx·placement group의 위치를 전부 결정합니다.
0-2. 용량 예약 — 두 경로 중 선택
| 경로 | PCS 설정 | 제약 | 적합 |
|---|---|---|---|
| Capacity Block for ML |
purchaseOption=CAPACITY_BLOCK + LT MarketType=capacity-block + CapacityReservationId |
블록당 최대 64대 · 합계 256대 · PCS는 CNG당 블록 1개, reservation group 불가 · 취소 불가 · placement group 불가 · 최대 8주 전 예약 | 기간이 정해진 대규모 학습 캠페인 |
| ODCR (targeted) |
purchaseOption=ONDEMAND + LT CapacityReservationTarget |
Running On-Demand P instances vCPU 쿼터 필요. 예약 ID 직접 참조 = 백필 없음, reservation group 참조 = 백필 가능 |
상시 운영 · 개발용 소규모 |
EC2 User Guide의 Capacity Block 지원 표에 p6-b300.48xlarge × Asia Pacific (Seoul) 체크가 있습니다(2026-09-14 확인). 서울에서 예약 가능한 P 계열은 현재 p6-b300.48xlarge와 p5en.48xlarge 두 종입니다. PCS도 P6-B300 계열에서 Capacity Block을 공식 지원합니다.
Capacity Block은 블록당 최대 64대이고 PCS는 CNG 하나에 블록 하나만 연결합니다(여러 블록을 묶은 capacity reservation group은 연결 불가). 따라서 125노드 = 최소 2개 블록 = 최소 2개 CNG입니다. 두 CNG를 같은 큐에 매핑하면 사용자에게는 하나의 파티션으로 보이므로 실사용에는 영향이 없습니다(CNG 한도 10개 안에서 여유).
EC2 문서 단서: "Capacity Block sizes of 64 instances are not supported for all instance types in all AWS Regions." 서울 p6-b300의 실제 최대 블록 크기를 확인하십시오 — 32대라면 CNG가 4개가 됩니다. 확인 필요
Capacity Block은 UTC 11:30에 종료되고, 마지막 날 UTC 11:00부터 인스턴스 종료 프로세스가 시작됩니다. KST 기준 20:00 종료 시작 / 20:30 완료입니다. 만료 시 CNG·큐 연결은 유지되지만 모든 인스턴스가 종료되고 실행 중 job은 실패, 대기 job은 pending에 멈춥니다. 복구는 새 블록을 가리키는 launch template으로 CNG를 업데이트해야 합니다.
학습 스크립트가 KST 19:30 이전에 최종 체크포인트를 저장하도록 계획하십시오. 예약 창 전체가 과금되고 조기 취소는 불가능합니다.
0-3. 쿼터 신청
| 쿼터 | 기본값 | 조정 | 125노드 기준 |
|---|---|---|---|
EC2 Running On-Demand P instances (vCPU) | 계정별 | Service Quotas | 24,000 vCPU (ODCR/On-Demand 경로만. Capacity Block은 미적용) |
| PCS 리전별 클러스터 수 | 5 | Service Quotas | 여유 |
| PCS 동시 생성 중 클러스터 | 1 | 조정 불가 | 자동화 파이프라인은 직렬화 |
| PCS 클러스터당 CNG 수 | 10 | Support case | login 1 + GPU 2~4 + CPU/MIG 여유 — 팀별 CNG 분리는 금방 소진 |
| PCS 클러스터당 큐 수 | 10 | Support case | 팀별 파티션 설계 전 확인 |
승인 리드타임이 이 프로젝트에서 가장 긴 대기 항목입니다. Capacity Block만 쓸 계획이면 불필요하지만, 두 경로를 섞을 가능성이 조금이라도 있으면 지금 신청하는 게 안전합니다. 쿼터는 확보만 해두고 쓰지 않아도 비용이 발생하지 않습니다.
0-4. 도구 준비
aws --version # pcs 서브커맨드가 있는 최신 AWS CLI v2
aws pcs list-clusters --region ap-northeast-2 # 권한·엔드포인트 확인 (pcs.ap-northeast-2.amazonaws.com)
PCS 문서에 CNG당 인스턴스 상한이 명시되어 있지 않습니다. 클러스터 사이즈(Medium 512)가 실효 한도로 보이지만, ODCR 경로에서 125노드를 단일 CNG로 둘지는 AWS 서비스팀 확인이 안전합니다. 확인 필요
네트워크 구축
D-71-1. 만들 것
- VPC — 권장
/16, DNS hostnames + DNS resolution 활성(PCS 요구사항) - 퍼블릭 서브넷 1개 — NAT Gateway, (선택) login 노드
- 프라이빗 GPU 서브넷 1개 — Step 0의 AZ,
/20 - 프라이빗 서브넷 1개 — login CNG / FSx 마운트타깃 / PCS 클러스터 ENI (GPU 서브넷과 분리)
- 클러스터 보안그룹 — 자기참조(self-referencing) all-traffic 인바운드/아웃바운드. PCS가 컨트롤러 ENI와 모든 노드에 붙이는 SG
- EFA 보안그룹 — 자기참조 all-traffic (EFA 트래픽은 SG 자기참조가 필수)
- (선택) SSH 보안그룹 — login 노드 22, 신뢰 CIDR만
- (선택) S3 / ECR / CloudWatch / SSM VPC 엔드포인트 — NAT 데이터 처리 비용 절감
AWS 공식 레시피 aws-hpc-recipes/recipes/net/hpc_large_scale이 PCS 요구사항을 만족하는 VPC를 만들어 줍니다. CIDR만 아래 표에 맞춰 조정하십시오.
1-2. GPU 서브넷 사이징 — 노드당 17 IP
| GPU 노드 | 필요 IP (17/노드) | 최소 서브넷 (가용 IP) |
|---|---|---|
| 2 | 34 | /26 (59) |
| 16 | 272 | /23 (507) |
| 32 | 544 | /22 (1,019) |
| 64 | 1,088 | /21 (2,043) |
| 125 | 2,125 | /20 (4,091) — /21은 부족 |
PCS 차이 ParallelCluster 3.15+는 secondary 카드를 efa-only로 만들어 노드당 IP를 1개로 줄이지만, PCS 레퍼런스 템플릿은 InterfaceType: efa를 요구합니다(awslabs 주석: "PCS requires InterfaceType: efa (not efa-only) to propagate the interface configuration to the launch instances request correctly."). PCS 공식 문서의 EFA 예제도 전부 efa입니다. → 노드당 17 IP로 계산하십시오. 서브넷은 나중에 키울 수 없습니다.
PoC에서 efa-only가 동작하는지 실측해 볼 가치는 있습니다(통하면 17→1). 다만 서브넷은 통하지 않는 경우를 기준으로 잡으십시오. 확인 필요
EC2는 네트워크 인터페이스가 2개 이상인 인스턴스에 퍼블릭 IP를 자동 할당하지 않습니다. 17-NIC p6-b300은 퍼블릭 서브넷에서 인터넷을 쓸 수 없어 PCS agent가 컨트롤러·S3에 닿지 못합니다. → 프라이빗 서브넷 + NAT Gateway(또는 VPC 엔드포인트)가 필수입니다.
PCS 문서: "If you select multiple subnets, EFA communications won't be available between nodes." CNG의 --subnet-ids에는 GPU 서브넷 하나만 넣으십시오. 1,000 GPU 중 일부를 EKS/HyperPod 등 다른 플랫폼에 둘 경우에도 PCS 쪽 GPU는 같은 AZ에 모아 EFA 지역성을 확보합니다.
공유 스토리지 생성 — 클러스터 외부에
D-5awslabs deploy-all.yaml은 편의상 VPC·FSx·PCS를 하나의 nested stack으로 만듭니다. PoC에는 좋지만, 그 스택을 지우면 FSx도 함께 지워집니다. 본운영 경로는 FSx를 별도 스택으로 먼저 만들고 클러스터 쪽에서는 파일시스템 ID로만 참조하십시오. 클러스터 사이즈 변경(§4 #1)으로 재생성하는 날 데이터가 살아 있는 유일한 방법입니다.
2-1. 계층 구조
| 마운트 | 서비스 | 용도 |
|---|---|---|
/fsx | FSx for Lustre PERSISTENT_2, PerUnitStorageThroughput 250 이상 | 학습 데이터, 체크포인트, 컨테이너 .sqsh 이미지 |
/home | FSx for OpenZFS (SINGLE_AZ_HA_2) 또는 EFS | 홈 디렉터리 (small file / metadata 위주) |
/opt/dlami/nvme | 로컬 NVMe (8 × 3.84 TB) | Enroot 오버레이, 데이터셋 로컬 캐시 — 휘발성. lifecycle action EVERY_BOOT로 RAID0+마운트 |
| — | S3 (+ Lustre DRA) | 원본 데이터셋, 체크포인트 아카이브 |
2-2. 만들 때 지킬 것
- FSx for Lustre를 GPU 서브넷과 같은 AZ에 생성 (AZ 간 전송 비용·지연 회피)
- 파일시스템 보안그룹에 클러스터 SG 인바운드 허용 (Lustre 988, 1018–1023 / OpenZFS 111·2049·20001–20003)
- S3 버킷 생성 + Lustre DRA(Data Repository Association) 연동
- 마운트는 PCS가 대신 해주지 않습니다 PCS 차이 — Step 3의 lifecycle action
mount-fsx.sh가 수행
PCS 문서의 명시적 경고: 마운트 실패/타임아웃은 인스턴스가 job 실행 가능 상태가 되지 못하게 만들고, 이는 예상치 못한 비용으로 이어집니다. 마운트 스크립트는 nodeBootstrapped 스테이지 + onError: TERMINATE로 두어 공유 스토리지 없는 노드가 큐에 들어오지 않게 하십시오(TERMINATE된 노드는 PCS가 교체합니다). nodeReady 스테이지는 slurmd가 이미 떠서 job이 배정될 수 있는 시점이라 늦습니다.
FSx for Lustre와 OpenZFS 모두 생성 후 용량·처리량 증설이 가능합니다(데이터 마이그레이션 없음). 큰 파일시스템은 생성 자체에 시간이 오래 걸려 초기 구축 전체를 지연시킵니다.
FSx for Lustre에 EFA를 켜면 GPU 메모리로 직접 DMA하는 GDS 경로를 쓸 수 있습니다(P5/P5e/P5en/P6-B200에서 지원). PERSISTENT_2 SSD 전용이고 최소 용량이 19,200 GiB로 올라갑니다. awslabs 지원 목록에 P6-B300이 명시되어 있지 않습니다 확인 필요 — 1단계에서는 켜지 말고, 스토리지가 실제 병목으로 확인된 뒤 검토하십시오.
AMI와 부트스트랩 (node lifecycle actions)
D-53-1. AMI — PCS-ready DLAMI를 ID로 고정
# 최신 PCS-ready DLAMI (Deep Learning Base GPU AMI, Ubuntu 24.04 기반)
aws ssm get-parameter --region ap-northeast-2 \
--name /aws/service/pcs/ami/dlami-base-ubuntu2404/x86_64/latest/ami-id \
--query "Parameter.Value" --output text
# Description에 소스 DLAMI 날짜 / PCS Agent 버전 / 내장 Slurm 버전이 적혀 있음 — 기록해 두십시오
aws ec2 describe-images --region ap-northeast-2 --image-ids ami-xxxxxxxx \
--query 'Images[0].[Name,Description,CreationDate]' --output table
| 포함 | 미포함 (직접 추가) |
|---|---|
| Ubuntu 24.04 · NVIDIA 드라이버 · CUDA · EFA 드라이버 · Lustre 클라이언트 · EFS utils · PCS Agent · Slurm for PCS(지원 버전 다중 내장, 클러스터 버전에 맞춰 자동 활성) | PyTorch 등 프레임워크(컨테이너로) · Enroot / Pyxis · DCGM exporter · 컴파일러·수학 라이브러리 |
/latest/를 CloudFormation에 직접 넣으면 AMI가 조용히 바뀝니다
{{resolve:ssm:/aws/service/pcs/ami/.../latest/ami-id}}는 stack update마다 재해석됩니다. 나중에 노드 수를 올리는 update가 새 AMI를 끌어와 드라이버·CUDA 버전이 노드마다 달라지는 상황이 생깁니다. awslabs 운영 가이드의 명시적 권고: AMI ID를 pin하고, 릴리스 SNS(arn:aws:sns:us-west-2:265886551188:pcs-ready-dlami-release-notifications)를 구독해 의도적으로 올리십시오.
Enroot/Pyxis를 lifecycle action으로 첫 부팅에 설치하면 노드 부팅이 ~8–12분, 커스텀 AMI에 미리 굽면 ~3분입니다. 125노드를 static으로 한 번에 올릴 때, 그리고 노드 교체마다 이 차이가 GPU 유휴 비용으로 곱해집니다. AWS가 EC2 Image Builder 템플릿(aws-hpc-recipes/recipes/pcs/dlami_for_pcs_imagebuilder, pcs-ready-dlami-with-enroot-pyxis.yaml)을 제공합니다. PCS 차이 커스텀 AMI는 임의 OS(AL2023/Ubuntu/RHEL/Rocky)에 AWS installer로 PCS agent + Slurm을 얹는 방식이라, 특정 CUDA/NCCL 버전 고정이 HyperPod보다 자유롭습니다.
3-2. Node lifecycle actions — user data 대신 이것을 쓰십시오
PCS Agent 1.5.0-1 이상에서 PCS가 지정 스테이지에 S3 스크립트를 내려받아 실행합니다(3회 재시도·백오프 내장, 스크립트별 로그). launch template user data보다 실패 처리와 관측이 훨씬 낫습니다.
| 스테이지 | 시점 | 여기에 둘 것 |
|---|---|---|
nodeBootstrapped | PCS 노드 셋업 완료 후, slurmd 시작 전 | job을 받기 전에 끝나야 하는 것 전부: 파일시스템 마운트, NVMe RAID, needrestart 가드, 헬스체크 스크립트 로컬 복사, 심층 GPU 진단, DCGM exporter |
nodeReady | slurmd 시작·등록 후 | Slurm 명령이 필요한 것(노드 feature 태깅 등). ⚠ 이 시점엔 이미 job이 배정될 수 있습니다 |
| 옵션 | 값 | 권장 |
|---|---|---|
onError | TERMINATE(기본) / CONTINUE | 마운트·GPU 진단 = TERMINATE(불량 노드는 교체됨). 모니터링 에이전트 = CONTINUE |
executionPolicy | FIRST_BOOT_ONLY(기본) / EVERY_BOOT | 마운트·RAID·MIG 등 재부팅 후 다시 필요한 것은 EVERY_BOOT(멱등하게 작성). scontrol reboot를 쓰려면 특히 중요 |
scriptSource | s3:// 또는 https://, 선택 s3VersionId·checksum(SHA-256) | 본운영은 버전 ID 또는 checksum 고정 — 스크립트 drift 방지 |
| 로그 | /var/log/amazon/pcs/lifecycle/actions/<stage>/<script-name>.log, 에이전트 executor.log. TERMINATE된 노드의 로그는 사라지므로 AWS 제공 configure-cloudwatch-logs.sh로 CloudWatch에 전송 | |
스크립트 안에서 reboot를 호출하면 PCS bootstrap 시퀀스가 깨집니다. 재부팅이 필요한 작업(MIG 모드 전환, 커널 파라미터)은 cloud-init boothook(early boot user data)으로 옮기십시오. 환경변수 PCS_IS_FIRST_BOOT(1/0)로 EVERY_BOOT 스크립트의 분기가 가능합니다.
3-3. 스크립트 목록 (S3 s3://${SCRIPT_BUCKET}/lifecycle/)
| 순서 | 스크립트 | 스테이지 · 정책 | 내용 |
|---|---|---|---|
| 1 | mount-fsx.sh | nodeBootstrapped · EVERY_BOOT · TERMINATE | /fsx Lustre(noatime,flock) + /home OpenZFS NFS 마운트, 실패 시 exit 1 |
| 2 | local-nvme.sh | nodeBootstrapped · EVERY_BOOT · TERMINATE | 8× NVMe RAID0 → /opt/dlami/nvme, Enroot 캐시 디렉터리 |
| 3 | node-hardening.sh | nodeBootstrapped · FIRST_BOOT_ONLY · CONTINUE | needrestart 가드(아래), Lustre 런타임 튜닝(3-4), 헬스체크 스크립트를 S3 → 로컬 /opt/ops/health로 복사 |
| 4 | install-enroot-pyxis.sh | nodeBootstrapped · FIRST_BOOT_ONLY · TERMINATE | awslabs 제공. pre-bake AMI에서는 제외 |
| 5 | gpu-healthcheck-startup.sh | nodeBootstrapped · EVERY_BOOT · TERMINATE | awslabs lightweight 스위트(nvidia-smi / DCGM L2 / EFA 열거 / 토폴로지). 실패 = 노드 교체(Step 8) |
| 6 | dcgm-exporter.sh | nodeBootstrapped · FIRST_BOOT_ONLY · CONTINUE | DCGM exporter(B300은 4.5.2 이상) + node exporter + EFA exporter |
| 7 | configure-cloudwatch-logs.sh | nodeBootstrapped · FIRST_BOOT_ONLY · CONTINUE | AWS 제공. lifecycle 로그·slurmd 로그를 CloudWatch Logs로 |
| 8 | warmup-srun.sh | nodeReady · EVERY_BOOT · CONTINUE | 알려진 이슈 회피용 버리는 srun(운영 주의사항) |
인스턴스 프로파일에 해당 버킷 s3:GetObject(+ s3:GetObjectVersion)와 CloudWatch Logs 쓰기 권한을 부여합니다.
Ubuntu 계열에서 unattended security upgrade가 slurmd가 링크한 라이브러리(glibc 등)를 갱신하면, needrestart가 slurmd를 재시작하고 그 노드에서 실행 중인 모든 job이 죽습니다. 재현되는 현상이며, awslabs PCS 템플릿은 lifecycle action으로 드롭인을 심어 막습니다. 자체 구성에서도 반드시 포함하십시오.
# /etc/needrestart/conf.d/90-pcs-slurm.conf
$nrconf{override_rc}{qr(^slurmd)} = 0;
3-4. 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)
lctl set_param llite.*.max_read_ahead_mb=1024
lctl set_param llite.*.statahead_max=512
디렉터리별 striping은 login 노드에서 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 오버헤드만 증가
클러스터 생성
D-3클러스터는 컨트롤러입니다. 노드는 아직 없습니다. 여기서 정하는 것은 사이즈·버전·accounting·클러스터 레벨 Slurm 파라미터입니다.
aws pcs create-cluster --region ap-northeast-2 \
--cluster-name llm-poc \
--scheduler type=SLURM,version=26.05 \
--size MEDIUM \
--networking subnetIds=${CTRL_SUBNET_ID},securityGroupIds=${CLUSTER_SG_ID} \
--slurm-configuration file://cluster-slurm.json
# 상태 확인 (CREATING → ACTIVE, 수 분~수십 분)
aws pcs get-cluster --region ap-northeast-2 --cluster-identifier llm-poc \
--query 'cluster.[status,endpoints,slurmConfiguration.authKey]' --output json
cluster-slurm.json — 클러스터 레벨 Slurm 파라미터(허용 목록 항목만):
{
"scaleDownIdleTimeInSeconds": 600,
"accounting": { "mode": "STANDARD", "defaultPurgeTimeInDays": 180 },
"slurmCustomSettings": [
{ "parameterName": "DefMemPerCPU", "parameterValue": "40000" },
{ "parameterName": "PreemptType", "parameterValue": "preempt/qos" },
{ "parameterName": "PreemptMode", "parameterValue": "REQUEUE" },
{ "parameterName": "JobRequeue", "parameterValue": "1" },
{ "parameterName": "PriorityWeightQOS", "parameterValue": "10000" },
{ "parameterName": "PriorityWeightFairshare", "parameterValue": "1000" },
{ "parameterName": "PriorityWeightAge", "parameterValue": "100" },
{ "parameterName": "AccountingStorageEnforce", "parameterValue": "limits,qos" },
{ "parameterName": "AccountingStorageTRES", "parameterValue": "cpu,mem,node,billing,gres/gpu" },
{ "parameterName": "HealthCheckProgram", "parameterValue": "/opt/ops/health/periodic-check.sh" },
{ "parameterName": "HealthCheckInterval", "parameterValue": "300" },
{ "parameterName": "HealthCheckNodeState", "parameterValue": "IDLE" },
{ "parameterName": "Prolog", "parameterValue": "/opt/ops/health/prolog-gpu-quick.sh" },
{ "parameterName": "Epilog", "parameterValue": "/opt/ops/health/epilog-on-failure.sh" },
{ "parameterName": "PrologFlags", "parameterValue": "Contain" }
]
}
| 설정 | 왜 이 값인가 |
|---|---|
--size MEDIUM | §4 #1. 변경 불가. login CNG까지 포함해 125노드 + 여유 |
version=26.05 | GPU affinity 자동 설정(25.11은 CNG마다 Sockets 수기), SPANK rolling 업그레이드 제약 해소. 2026-09-10 출시로 매우 최근이라 보수적으로는 25.11 |
accounting STANDARD | QoS·GrpTRES 강제의 전제. DB는 AWS 관리(slurmdbd.conf 접근 불가). UpdateCluster로 사후 on/off 가능. 시간당 요금 있음(비용) |
AccountingStorageEnforce=limits,qos | limits가 associations를 내포. 이 순간부터 sacctmgr에 없는 사용자는 제출 거부 — 켜기 전 사용자 목록 준비(Step 7) |
DefMemPerCPU=40000 | 96 CPU × 40 GB ≈ 3.84 TB. PCS 허용 목록에 DefMemPerGPU·DefCpuPerGPU는 없음 → 사용자가 --gres=gpu:8 --cpus-per-task=12로 명시 |
Prolog/Epilog/HealthCheckProgram | 반드시 로컬 디스크 경로. /fsx에 두면 Lustre 장애 = 전 노드 prolog 실패 = 전 노드 DRAIN(Step 8). 클러스터 레벨 설정이라 모든 CNG(login 포함)에 적용됨 → 스크립트는 GPU 없는 노드에서 exit 0으로 통과하게 작성 |
PCS는 허용 목록 방식입니다. 클러스터 레벨에 Prolog·Epilog·HealthCheck*·Preempt*·JobRequeue·RequeueExit·PriorityWeight*·AccountingStorageEnforce·SchedulerParameters·SlurmctldParameters·MinJobAge·DefMemPerCPU·MetricsType 등 약 50개가 열려 있습니다.
없는 것 중 이 설계에 영향이 큰 것: KillWait(SIGTERM→SIGKILL 간격, 기본 30초 고정), DefMemPerGPU/DefCpuPerGPU, PriorityType/SchedulerType(PCS가 관리), 파티션의 Hidden/AllowGroups. 체크포인트 여유는 GraceTime(큐 레벨) + 사용자 --signal로 만듭니다(Step 8). 목록은 PCS 문서 slurm-custom-settings-cluster/-queue/-cng에서 버전별로 확인하십시오.
Creating 상태 클러스터는 리전당 1개(조정 불가)입니다. dev/prod 두 클러스터를 CI로 동시에 만들면 두 번째가 실패합니다. 직렬로 만드십시오.
Launch Template — 17-NIC, 이 문서에서 가장 중요한 블록
D-2PCS 차이 ParallelCluster의 Efa: Enabled: true에 해당하는 스위치가 PCS에는 없습니다. EC2 launch template에 17개 네트워크 인터페이스를 직접 정의하고, CNG가 그 템플릿을 참조합니다. 가장 빠른 길은 awslabs add-cng-p6-b300.yaml(p6-b300 전용 CloudFormation)을 그대로 쓰거나 그 launch template 부분을 가져오는 것입니다.
5-1. 규칙 — P5/P6-B200 템플릿을 복사하면 실패합니다
| p5 / p6-b200 | p6-b300 | |
|---|---|---|
| card 0 | EFA (ENA+EFA) | ENA 전용, InterfaceType 생략 |
| EFA 카드 | card 1~N, DeviceIndex 1 | card 1–16, 전부 DeviceIndex 0 |
| 인터페이스 수 | 32 등 | 17 |
5-2. launch template 본문 (요지)
LaunchTemplateData:
ImageId: ami-xxxxxxxx # Step 3에서 pin한 PCS-ready DLAMI / 커스텀 AMI
IamInstanceProfile: { Arn: ${INSTANCE_PROFILE_ARN} } # CNG의 --iam-instance-profile-arn과 동일
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs: { VolumeSize: 500, VolumeType: gp3, DeleteOnTermination: true }
Placement: # ODCR/On-Demand 경로만. Capacity Block이면 이 블록 삭제
GroupId: ${CLUSTER_PLACEMENT_GROUP_ID}
CapacityReservationSpecification: # ODCR
CapacityReservationTarget: { CapacityReservationId: ${CR_ID} }
# Capacity Block이면 위 블록 대신:
# InstanceMarketOptions: { MarketType: capacity-block }
# CapacityReservationSpecification: { CapacityReservationTarget: { CapacityReservationId: cr-xxxx } }
MetadataOptions: { HttpTokens: required, HttpPutResponseHopLimit: 2 }
NetworkInterfaces:
# ---- card 0: ENA 전용 (InterfaceType 지정하지 않음). 일반 트래픽 SG는 여기에만 ----
- DeviceIndex: 0
NetworkCardIndex: 0
SubnetId: ${GPU_SUBNET_ID}
Groups: [${CLUSTER_SG_ID}, ${EFA_SG_ID}]
DeleteOnTermination: true
# ---- card 1~16: EFA. DeviceIndex는 전부 0 ----
- DeviceIndex: 0
NetworkCardIndex: 1
InterfaceType: efa # efa-only 아님 (5-3)
SubnetId: ${GPU_SUBNET_ID}
Groups: [${EFA_SG_ID}]
DeleteOnTermination: true
# ... NetworkCardIndex 2 ~ 16 동일하게 반복 (총 16개) ...
TagSpecifications:
- ResourceType: instance
Tags: [{ Key: Project, Value: llm-training }]
5-3. 반드시 지킬 것 5가지
InterfaceType: efa(efa-only아님). awslabs 주석: "PCS requiresInterfaceType: efa(notefa-only) to propagate the interface configuration to the launch instances request correctly." → 노드당 17 IP(Step 1).SecurityGroupIds(템플릿 최상위)를 쓰지 마십시오.NetworkInterfaces를 정의한 템플릿에서는 각 인터페이스의Groups로만 SG를 지정해야 합니다. 클러스터 SG는 primary에, EFA SG는 전부에.pcs-<id>-do-not-delete이름의 PCS 관리형 템플릿을 CNG에 지정하지 마십시오.- 템플릿 버전 추적. CNG를
version=1로 고정하면 이후 템플릿 수정이 노드에 반영되지 않습니다. CloudFormation이면!GetAtt LaunchTemplate.LatestVersionNumber, CLI면version='$Latest'또는 수정 후 CNG 업데이트. - user data는 비워두거나 최소로. 부트스트랩 로직은 lifecycle actions(Step 3)로. 단 MIG 모드 전환처럼 재부팅이 필요한 것만
cloud-init boothook으로 여기에.
EC2 문서 명시: "Capacity Blocks do not support placement groups." Capacity Block 경로의 launch template에는 Placement.GroupId를 넣지 마십시오(launch 실패). 근접 배치는 UltraCluster가 자체적으로 처리합니다. 반대로 ODCR/On-Demand 경로에서는 반드시 cluster placement group을 만들어 지정하십시오 — 안 넣으면 노드가 흩어져 EFA 지연이 늘어납니다.
aws ec2 run-instances --region ap-northeast-2 --dry-run \
--launch-template LaunchTemplateId=${LT_ID},Version='$Latest' \
--instance-type p6-b300.48xlarge --count 1
# "DryRunOperation" = 템플릿·서브넷·SG·용량 예약 참조가 문법적으로 유효. "InvalidParameter..."면 배선 오류
Compute Node Group 생성
D-26-1. Login CNG (PoC) — 본운영은 standalone 권장
aws pcs create-compute-node-group --region ap-northeast-2 \
--cluster-identifier llm-poc \
--compute-node-group-name login \
--subnet-ids ${LOGIN_SUBNET_ID} \
--custom-launch-template id=${LOGIN_LT_ID},version='$Latest' \
--iam-instance-profile-arn ${INSTANCE_PROFILE_ARN} \
--ami-id ${AMI_ID} \
--scaling-configuration minInstanceCount=2,maxInstanceCount=2 \
--instance-configs instanceType=m6i.4xlarge \
--purchase-option ONDEMAND \
--node-lifecycle-actions file://lifecycle-login.json
① 노드 관리 요금(Standard $0.101/인스턴스·시간)이 빠집니다. ② 클러스터 "관리 인스턴스" 수에서 빠집니다. PCS 문서의 standalone login 노드 절차(working-with_login-nodes_standalone)와 aws-hpc-recipes/recipes/pcs/byo_login이 있고, 한 login 노드를 여러 클러스터에 연결하는 스크립트도 제공됩니다. PoC는 CNG로 빠르게, 본운영 전환 시 standalone으로 바꾸십시오.
6-2. GPU CNG — 전량 static
aws pcs create-compute-node-group --region ap-northeast-2 \
--cluster-identifier llm-poc \
--compute-node-group-name gpu-b300-a \
--subnet-ids ${GPU_SUBNET_ID} # ⚠ 단일 서브넷 = 단일 AZ \
--custom-launch-template id=${GPU_LT_ID},version='$Latest' \
--iam-instance-profile-arn ${INSTANCE_PROFILE_ARN} \
--ami-id ${AMI_ID} \
--scaling-configuration minInstanceCount=2,maxInstanceCount=2 # static. 2 → 16 → 64 \
--instance-configs instanceType=p6-b300.48xlarge \
--purchase-option ONDEMAND # Capacity Block이면 CAPACITY_BLOCK \
--slurm-configuration 'slurmCustomSettings=[{parameterName=Features,parameterValue=b300},{parameterName=Weight,parameterValue=10}]' \
--node-lifecycle-actions file://lifecycle-gpu.json
lifecycle-gpu.json (Step 3의 스크립트 목록을 그대로 옮긴 것):
{ "stages": {
"nodeBootstrapped": [
{ "name": "Mount FSx", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/mount-fsx.sh" },
"arguments": ["${FSX_ID}", "${FSX_MOUNT_NAME}", "${OPENZFS_DNS}"], "executionPolicy": "EVERY_BOOT", "onError": "TERMINATE" },
{ "name": "Local NVMe", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/local-nvme.sh" },
"executionPolicy": "EVERY_BOOT", "onError": "TERMINATE" },
{ "name": "Node hardening", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/node-hardening.sh" },
"executionPolicy": "FIRST_BOOT_ONLY", "onError": "CONTINUE" },
{ "name": "Install Enroot Pyxis", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/install-enroot-pyxis.sh" },
"executionPolicy": "FIRST_BOOT_ONLY", "onError": "TERMINATE" },
{ "name": "GPU healthcheck startup", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/gpu-healthcheck-startup.sh" },
"executionPolicy": "EVERY_BOOT", "onError": "TERMINATE" },
{ "name": "DCGM exporter", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/dcgm-exporter.sh" },
"executionPolicy": "FIRST_BOOT_ONLY", "onError": "CONTINUE" },
{ "name": "CloudWatch logs", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/configure-cloudwatch-logs.sh" },
"arguments": ["/aws/pcs/llm-poc"], "executionPolicy": "FIRST_BOOT_ONLY", "onError": "CONTINUE" }
],
"nodeReady": [
{ "name": "Warmup srun", "scriptSource": { "scriptLocation": "s3://${SCRIPT_BUCKET}/lifecycle/warmup-srun.sh" },
"executionPolicy": "EVERY_BOOT", "onError": "CONTINUE" }
]
} }
Sockets를 넣지 않으면 노드가 INVALID_REG로 drain됩니다
25.11에서는 GPU autodetect(AutoDetect=nvml)가 CPU 토폴로지와 맞지 않으면 노드 등록이 실패합니다. CNG slurmCustomSettings에 Sockets(p6-b300의 NUMA 도메인 수 확인 필요)와 gresCustomSettings=[{AutoDetect=nvml}]를 넣어야 합니다. 26.05는 PCS가 NUMA 토폴로지와 GPU affinity(AutoDetect=full)를 기본 설정하므로 이 작업이 필요 없습니다. 이 문서가 26.05를 권장하는 실질적 이유입니다.
6-3. Capacity Block 경로 — CNG를 블록 수만큼
# 블록 1 (최대 64대) → CNG gpu-b300-a, LT-A(cr-aaaa 참조)
aws pcs create-compute-node-group ... --compute-node-group-name gpu-b300-a \
--custom-launch-template id=${LT_A},version='$Latest' \
--scaling-configuration minInstanceCount=64,maxInstanceCount=64 \
--purchase-option CAPACITY_BLOCK ...
# 블록 2 (61대) → CNG gpu-b300-b, LT-B(cr-bbbb 참조)
aws pcs create-compute-node-group ... --compute-node-group-name gpu-b300-b \
--custom-launch-template id=${LT_B},version='$Latest' \
--scaling-configuration minInstanceCount=61,maxInstanceCount=61 \
--purchase-option CAPACITY_BLOCK ...
# 두 CNG를 하나의 큐에 매핑 → 사용자에게는 단일 파티션 (Step 7)
- 블록마다 launch template이 따로 필요합니다(
CapacityReservationId가 다름). - 블록이
scheduled여도 CNG를 만들 수 있고, active가 되면 노드가 올라옵니다. 상태가payment-failed등이면 사용 불가. - min = max = 예약 수량으로 두십시오. 예약 창 전체가 과금되므로 0에서 올리면 유휴 시간이 낭비입니다.
- 만료 후 복구 = 새 블록을 참조하는 새 LT 버전으로 CNG 업데이트(운영 주의사항).
aws pcs list-compute-node-groups --region ap-northeast-2 --cluster-identifier llm-poc
aws pcs get-compute-node-group --region ap-northeast-2 --cluster-identifier llm-poc \
--compute-node-group-identifier gpu-b300-a --query 'computeNodeGroup.[status,errorInfo]'
# 노드가 안 올라오면: EC2 콘솔 인스턴스 상태 → /var/log/amazon/pcs/ (SSM) → CloudWatch Logs(lifecycle)
큐 · QoS · 멀티팀 운영
D-1 ~ D+1큐의 AllowQos/DenyQos/QOS에 쓰는 QoS는 accounting DB에 먼저 존재해야 합니다. 없으면 Slurm 25.11부터 slurmctld가 fatal error로 종료됩니다(릴리스 노트 명시). 반드시 이 순서로 진행하십시오.
① accounting 활성(Step 4) → ② login 노드에서 sacctmgr로 계정·사용자·QoS 생성 → ③ 큐에 AllowQos 설정 → ④ 검증. ②를 건너뛰고 AccountingStorageEnforce가 적용되면 등록되지 않은 사용자는 어떤 큐에도 제출할 수 없습니다. "갑자기 제출이 안 된다"는 신고의 첫 확인 항목: sacctmgr show assoc user=<name>.
7-1. 두 계층의 역할 — 큐만으로는 독점을 막을 수 없습니다
| Queue (Slurm partition) | Slurm Accounting (QoS) | |
|---|---|---|
| 제어 단위 | 큐 | 사용자 / 계정 / QoS |
| 가능한 제약 | MaxTime, PriorityTier, PreemptMode, GraceTime, AllowQos/AllowAccounts | 사용자별 동시 실행/제출 수, 팀별 GPU·CPU·메모리 총량(GrpTRES) |
| 강제력 | Slurm 기본 동작 | AccountingStorageEnforce로 강제 |
| 역할 | 자원 배분의 틀 | 실제로 강제하고 기록하는 시스템 |
7-2. 계정과 QoS 생성 (login 노드에서)
# 팀 계정
sacctmgr --immediate add account team-a Description="Team A"
sacctmgr --immediate add account team-b Description="Team B"
# 사용자 등록 (OS 계정이 먼저 존재해야 함 — SSSD/LDAP 또는 로컬)
sacctmgr --immediate add user name=alice 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 MaxWall=00:30:00
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 PreemptMode=REQUEUE Preempt=normal_qos,large_qos
# ★ 팀별 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
7-3. 큐 생성 — CNG 매핑 + 파티션 레벨 설정
# 두 CNG(gpu-b300-a, gpu-b300-b)를 하나의 파티션으로. Capacity Block 2블록이면 이렇게
for q in debug normal large exclusive; do :; done # 아래 4개를 각각 생성
aws pcs create-queue --region ap-northeast-2 --cluster-identifier llm-poc \
--queue-name normal \
--compute-node-group-configurations computeNodeGroupId=${CNG_A_ID} computeNodeGroupId=${CNG_B_ID} \
--slurm-configuration 'slurmCustomSettings=[
{parameterName=AllowQos, parameterValue=normal_qos},
{parameterName=MaxTime, parameterValue=1-00:00:00},
{parameterName=PriorityTier, parameterValue=2},
{parameterName=GraceTime, parameterValue=600},
{parameterName=Default, parameterValue=YES}]'
aws pcs create-queue ... --queue-name debug --compute-node-group-configurations computeNodeGroupId=${CNG_A_ID} \
--slurm-configuration 'slurmCustomSettings=[{parameterName=AllowQos,parameterValue=debug_qos},{parameterName=MaxTime,parameterValue=00:30:00},{parameterName=PriorityTier,parameterValue=1},{parameterName=GraceTime,parameterValue=120}]'
aws pcs create-queue ... --queue-name large --compute-node-group-configurations computeNodeGroupId=${CNG_A_ID} computeNodeGroupId=${CNG_B_ID} \
--slurm-configuration 'slurmCustomSettings=[{parameterName=AllowQos,parameterValue=large_qos},{parameterName=MaxTime,parameterValue=7-00:00:00},{parameterName=PriorityTier,parameterValue=3},{parameterName=GraceTime,parameterValue=600}]'
aws pcs create-queue ... --queue-name exclusive --compute-node-group-configurations computeNodeGroupId=${CNG_A_ID} computeNodeGroupId=${CNG_B_ID} \
--slurm-configuration 'slurmCustomSettings=[{parameterName=AllowQos,parameterValue=exclusive_qos},{parameterName=MaxTime,parameterValue=14-00:00:00},{parameterName=PriorityTier,parameterValue=10},{parameterName=PreemptMode,parameterValue=REQUEUE}]'
| 설정 | 왜 |
|---|---|
PreemptType=preempt/qos(클러스터) + QoS Preempt= | PCS 큐 레벨 허용 목록에 Priority(partition_prio용)가 없고 PriorityTier만 있으므로, 선점은 QoS 기반으로 설계합니다. exclusive_qos가 normal/large를 REQUEUE로 선점 |
GraceTime=600 | 선점당한 job에 SIGTERM 후 600초 유예. KillWait는 PCS에서 바꿀 수 없으므로(기본 30초) 시간 초과 시의 여유는 사용자 --signal로만 확보(Step 8) |
Default=YES | PCS 차이 PCS가 임의로 만드는 파티션이 없으므로 기본 파티션도 직접 지정. 하나만 YES |
| 큐 4개 + CNG 2~4개 | 기본 한도 큐 10 / CNG 10. 팀별로 큐를 더 쪼갤 계획이면 Step 0에서 한도 증설 |
GrpTRES=gres/gpu=N + AccountingStorageEnforce=limits. 이 조합이 있어야 팀이 배정량을 넘겨 제출할 때 실제로 거부됩니다. 둘 중 하나만 있으면 제한이 기록만 되고 강제되지 않습니다.
sacct --state=...는-E now를 명시하지 않으면 조용히 빈 결과를 반환합니다.sreport는 시간별 롤업을 따라가므로 최신 데이터가 반영되지 않습니다. 실시간 조회는sacct를 쓰십시오.
GPU 헬스체크와 복원력 — PCS에는 관리형 auto-healing이 없습니다
D+1PCS 문서 전체에서 HyperPod의 deep health check·자동 노드 교체에 해당하는 관리형 기능을 찾을 수 없습니다. "PCS도 auto-healing이 됩니다"라고 전제하면 안 됩니다. 정확한 표현은 "PCS는 auto-healing을 제공하지 않고, Slurm 훅과 lifecycle action으로 직접 구현하는 구조"입니다. 재료는 전부 열려 있고(HealthCheckProgram·Prolog·Epilog·lifecycle TERMINATE·scontrol reboot·JobRequeue), awslabs가 DCGM 기반 스위트를 제공합니다. 1,000 GPU가 며칠씩 도는 환경에서 누가 이것을 만들고 운영할지를 착수 전에 정하십시오.
8-1. 5단계 배치
| 시점 | 어디에 | 무엇을 | 실패 시 |
|---|---|---|---|
| ① 노드 기동 | lifecycle nodeBootstrappedonError: TERMINATE |
awslabs lightweight 스위트: nvidia-smi(Xid/ECC/retired page) · DCGM level-2 · EFA 열거(16) · 토폴로지. 수 분 | 노드가 큐에 들어오지 않고 종료·교체 — PCS가 TERMINATE된 노드를 교체합니다(문서 명시). 로그는 CloudWatch로 미리 전송 |
| ② job 시작 전 | Slurm prolog (클러스터 레벨) | nvidia-smi + 커널로그 Xid 스캔 + GPU 8개 + EFA 16 + CUDA_VISIBLE_DEVICES 비어있지 않은지. 수 초 이내 |
노드 DRAIN + job requeue(prolog 실패 시 Slurm 기본 동작) |
| ③ job 종료 후 | Slurm epilog | job이 실패했을 때만 DCGM level-2 → 다음 job 전에 열화 GPU 격리 | 노드 DRAIN(Reason 기록) |
| ④ 주기적 | HealthCheckProgram 5분, IDLE |
온도·ECC·NVLink 상태. 가볍게 | 노드 DRAIN |
| ⑤ 정비 창 | maintenance reservation 안에서 sbatch |
awslabs intensive(DCGM level-4 EUD·pulse power, NCCL, EFA loopback). 노드당 45분–2.25시간 | REBOOT / ISOLATE 판정에 따라 처리 |
8-2. DRAIN된 노드는 어떻게 되돌리나 — 두 경로
ParallelCluster의 clustermgtd는 DRAIN된 static 노드를 자동 교체하지만, PCS에 그런 동작이 있다는 문서 근거는 없습니다 확인 필요. DRAIN된 노드는 과금되면서 유휴 상태로 남습니다. 따라서 (a) scontrol reboot 또는 (b) 인스턴스 종료를 스크립트나 운영자가 명시적으로 수행해야 합니다. (b)의 근거는 "static CNG는 min 수량을 유지한다"와 "lifecycle TERMINATE 노드는 교체된다"는 두 문서 사실이며, 수동 종료 시에도 동일하게 교체되는지는 PoC 장애 리허설(Step 9)에서 실측하십시오.
자동화한다면 epilog/HealthCheckProgram에서 하드 결함 판정 시 aws ec2 terminate-instances $(ec2-metadata -i)를 호출하는 방식이 가장 단순합니다. 인스턴스 프로파일에 자기 자신만 종료할 수 있는 조건(ec2:ResourceTag/aws:pcs:compute-node-group-id 등)을 거십시오.
prolog가 실패하면 Slurm이 그 노드를 DRAIN합니다. prolog/epilog/HealthCheckProgram을 /fsx에 두면 Lustre가 잠깐 마운트를 잃는 순간 모든 노드의 prolog가 동시에 실패 → 전 노드 DRAIN입니다. 스크립트는 lifecycle action(node-hardening.sh)이 S3에서 로컬 /opt/ops/health로 복사해 두고, prolog는 GPU·EFA 결함 이외의 실패(스토리지·네트워크)에는 exit 0으로 끝내고 로그만 남기십시오. 클러스터 레벨 prolog는 login CNG에도 적용되므로 GPU가 없는 노드에서는 즉시 exit 0 해야 합니다.
8-3. job 내결함성 — KillWait를 바꿀 수 없다는 전제에서
JobRequeue=1(클러스터) +sbatch --requeue로 제출. 프레임워크 특정 종료코드는RequeueExit에 등록- 선점 시 유예 = 큐
GraceTime=600(SIGTERM → SIGKILL 600초) - 시간 초과·scancel 시 유예 = PCS 차이
KillWait(기본 30초)가 허용 목록에 없어 늘릴 수 없습니다. → 사용자 측sbatch --signal=B:USR1@600으로 종료 600초 전 시그널을 받아 체크포인트를 저장하고 스스로 종료하는 것이 유일한 수단입니다. 학습 스크립트 템플릿에 기본 포함시키십시오 UnkillableStepTimeout은 허용 목록에 있지만 체크포인트와 무관합니다(SIGKILL 후에도 죽지 않는 프로세스를 이상 판정하기까지의 대기시간). 공개 예제의 "체크포인트 시간 확보" 설명은 오해입니다
8-4. 스크립트 골격
동작 원리를 보이기 위한 최소 골격입니다. 판정 기준(Xid 목록, 온도, 재시도)은 2노드 검증에서 실측 후 확정하십시오. 네 파일 모두 node-hardening.sh가 S3에서 /opt/ops/health/로 복사합니다.
# node-hardening.sh (nodeBootstrapped, FIRST_BOOT_ONLY)
#!/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-pcs-slurm.conf
fi
if mountpoint -q /fsx; then bash /opt/ops/health/lustre-tuning.sh || true; fi
# prolog-gpu-quick.sh — 수 초 이내. GPU/EFA 결함만 실패(exit 1). GPU 없는 노드(login)는 즉시 통과
#!/bin/bash
command -v nvidia-smi >/dev/null 2>&1 || exit 0
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
command -v dcgmi >/dev/null 2>&1 || exit 0
[ "${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"
# 하드 결함 자동 교체를 택했다면: aws ec2 terminate-instances --instance-ids $(ec2-metadata -i | cut -d' ' -f2)
fi
exit 0
# periodic-check.sh (HealthCheckProgram, IDLE 노드에서 5분마다) — 가볍게
#!/bin/bash
command -v nvidia-smi >/dev/null 2>&1 || exit 0
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 (nodeBootstrapped, EVERY_BOOT, TERMINATE) — job 없음, 수 분 허용. exit≠0 → 노드 종료·교체
#!/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 2
# 또는 awslabs 스위트: /opt/ops/health/gpu-cluster-healthcheck/run-lightweight.sh
검증 — 2노드에서 전부 통과시킬 항목
D+2 ~ D+59-1. 인프라 기본 (login 노드에서)
sinfo -N -l
scontrol show nodes | grep -E 'NodeName|State|CfgTRES|Gres|Sockets|CPUTot'
# 기대: CPUTot=96 (SMT 비활성), Gres=gpu:8, State=idle
scontrol show partition | grep -E 'PartitionName|Default|AllowQos|GraceTime|MaxTime'
# 기대: normal이 Default=YES, 각 큐에 AllowQos
# GPU 인식 — 8개
srun -p normal -N1 --gres=gpu:8 --cpus-per-task=12 nvidia-smi
# EFA 열거 — 16 디바이스
srun -p normal -N1 fi_info -p efa | grep -c domain
srun -p normal -N1 ls /sys/class/infiniband/
# 스토리지 · lifecycle 로그
df -h /fsx /home /opt/dlami/nvme
lfs df -h /fsx
srun -p normal -N1 ls /var/log/amazon/pcs/lifecycle/actions/nodeBootstrapped/
9-2. NCCL 다중 노드 — 가장 중요한 성능 검증
# 컨테이너 이미지 (태그 고정). enroot는 '#' 레지스트리 구분자를 씁니다
enroot import -o /fsx/containers/nccl-tests.sqsh \
"docker://public.ecr.aws#hpc-cloud/nccl-tests:<tag>"
# 2노드 / 16 GPU all_reduce (awslabs nccl-tests-container.sbatch 참고)
srun -p normal -N2 --ntasks-per-node=8 --gres=gpu:8 --cpus-per-task=12 \
--container-image=/fsx/containers/nccl-tests.sqsh \
all_reduce_perf -b 8 -e 16G -f 2 -g 1
합격 기준
- 로그에
NET/OFI Selected provider is efa와found 16 nics # Out of bounds values : 0/OK- busbw가 메시지 크기에 따라 증가하고 대형 메시지에서 포화. Grafana EFA 대시보드에서 16 디바이스 모두 트래픽
found 16 nics가 아니라 1이나 8로 나오면 17-NIC 정의가 잘못 붙은 것입니다(P5용 DeviceIndex 1을 복사한 경우가 대표적). 이 상태로도 job은 돌지만 대역폭이 몇 분의 일로 떨어집니다.
awslabs 공개치는 p6-b200 4노드 all_reduce 377 GB/s뿐입니다. p6-b300 기준치는 확인하지 못했습니다 확인 필요. 자사 실측값을 기준선으로 기록하고 노드 교체·확장 시 회귀 판정에 쓰십시오.
9-3. 스토리지 성능
- Lustre 튜닝 적용 전/후 순차 쓰기 처리량 비교
- 실제 체크포인트 저장 1회 소요시간 측정 → Capacity Block 종료 시각(KST 20:00) 계획에 사용
- 로컬 NVMe 캐시 적용 시 데이터 로딩 시간 변화
- 노드 부팅 →
idle까지 소요시간 (DLAMI+lifecycle vs pre-bake) → 125노드 기동 시간 외삽
9-4. 장애 리허설 필수 — MTTR을 숫자로
| 시나리오 | 확인할 것 |
|---|---|
lifecycle gpu-healthcheck-startup.sh에 결함 주입(exit 1) | 노드가 TERMINATE되고 PCS가 새 인스턴스를 올리는지, CloudWatch에 로그가 남았는지 |
| prolog 빠른 체크 | job 시작 지연이 수 초 이내; 결함 주입 시 DRAIN + requeue |
| 인스턴스 강제 종료(콘솔) | static CNG가 수량을 회복하는지, job requeue → 체크포인트 재개까지 MTTR 측정 |
scontrol update State=DRAIN 후 방치 | 아무 일도 일어나지 않는지(PCS 자동 교체 없음 확인) → 운영 절차에 반영 확인 필요 |
scontrol reboot ASAP nextstate=RESUME | 재부팅 후 EVERY_BOOT 스크립트(마운트·NVMe·GPU 체크)가 다시 돌고 노드가 복귀하는지 |
| epilog | job 실패 시 level-2 진단이 돌고 결함 노드가 격리되는지 |
--signal=B:USR1@600 job을 scancel | 실제로 체크포인트가 남는지 |
| needrestart 가드 | needrestart -b 출력에 slurmd가 재시작 대상에서 빠졌는지 |
PCS는 auto-healing이 없으므로 "노드 하나가 죽었을 때 몇 분 만에 복구되는가"가 HyperPod과의 비교에서 결정적 데이터입니다. 감으로 넘기지 말고 측정해서 기록하십시오.
9-5. 멀티유저
GrpTRES=gres/gpu=N초과 제출이 실제로 거부되는지MaxJobsPerUser초과 제출이 막히는지exclusive_qosjob이normaljob을 실제로 preempt(requeue)하고 GraceTime이 지켜지는지- 미등록 사용자의 제출이 거부되는지 (그리고 에러 메시지가 무엇인지 — 운영 FAQ에 기록)
sacct -a -S <date> -E now로 사용자별 집계가 나오는지
확장과 버전 업그레이드 — 2 → 16 → 125노드
D+7 이후10-1. 노드 수 확장
# ODCR/On-Demand 경로: min/max만 올림 (fleet 정지 불필요)
aws pcs update-compute-node-group --region ap-northeast-2 --cluster-identifier llm-poc \
--compute-node-group-identifier gpu-b300-a \
--scaling-configuration minInstanceCount=16,maxInstanceCount=16
# Capacity Block 경로: 블록마다 CNG 추가 → 기존 큐에 매핑 추가
aws pcs create-compute-node-group ... --compute-node-group-name gpu-b300-b --purchase-option CAPACITY_BLOCK ...
aws pcs update-queue --region ap-northeast-2 --cluster-identifier llm-poc --queue-name normal \
--compute-node-group-configurations computeNodeGroupId=${CNG_A_ID} computeNodeGroupId=${CNG_B_ID}
| 변경 내용 | 영향 |
|---|---|
min/max 증가 | 실행 중 job 영향 없음. 새 노드는 lifecycle 스위트 통과 후 합류 |
| CNG 추가 + 큐 매핑 | 영향 없음. CNG 10개 한도 확인 |
min/max 감소 | PCS가 유휴 노드부터 종료. 제거 대상 노드에 먼저 maintenance reservation을 걸어 새 job 유입을 막으십시오 |
| launch template 수정 (AMI·CR ID 교체) | 새 버전 발행 → CNG가 $Latest면 이후 launch되는 노드부터 반영. 기존 노드는 교체(재launch)되어야 새 템플릿 적용 |
| 클러스터 사이즈 | 변경 불가 → 재생성. Medium으로 시작했으면 512까지 필요 없음 |
- 팀별
GrpTRES쿼터 — 총량이 늘었으니 재배분 - FSx 용량·처리량 — 노드 수에 비례해 스토리지 부하 증가
- 서브넷 IP 여유 — 17 IP/노드. 125노드 직전
/20에 4,091 중 2,125 소비 - Capacity Block 경로면 CNG·LT 추가 — 블록당 64대 한도
- 정비 창 계획 — 125노드 intensive 헬스체크는 노드당 최대 2.25시간. 병렬로 돌리되 학습 일정과 조율
- MinJobAge / 클러스터 job 추적 수 — 하이퍼파라미터 스윕처럼 짧은 job을 대량 던지면 Medium의 8,192 한도가 먼저 찹니다
10-2. Slurm 버전 업그레이드 — 클러스터 재생성 없음 PCS 차이
aws pcs update-cluster --region ap-northeast-2 --cluster-identifier llm-poc \
--scheduler type=SLURM,version=26.05 \
--client-token $(uuidgen)
| Option 1 · Rolling | Option 2 · Full-fleet 정지 | |
|---|---|---|
| 실행 중 job | 종료 불필요(노드는 컨트롤러 없이도 job을 계속 실행) | 전부 종료 |
| 컴퓨트 fleet | 일시적 버전 혼재 → 노드를 순차 drain·재부팅 | 전량 새 버전으로 재시작 |
| 제약 | SPANK 플러그인 사용 시 25.11 이하에서 불가(26.05부터 해소). CLI Filter 사용 시 25.05 이하 불가 | 없음 |
- 업그레이드 중 컨트롤러 일시 중단: 신규 제출·스케줄러 명령·자동 스케일링 정지, 실행 중 job은 계속(Option 1). accounting 데이터 보존
- 한 번에 3개 메이저 버전 이상 건너뛰기 불가. 패치 버전은 PCS가 자동 적용
- EOL 후에는 신규 클러스터 생성 불가, 기존 클러스터는 최대 12개월 무보증 운영. 25.05는 2026-11-30 EOL
- DLAMI는 지원 Slurm 버전을 다중 내장하므로 컨트롤러 업그레이드 시 노드 AMI 교체가 필수는 아니지만, EOL 근접 AMI는 pin을 갱신하십시오
운영 상시 주의사항
KST 20:00부터 노드가 종료되기 시작해 20:30에 끝납니다. 만료 시 CNG·큐 연결은 유지되지만 모든 인스턴스 종료, 실행 중 job 실패, 대기 job pending 정지. 만료 전 새 블록을 예약하고 launch template 새 버전에 CapacityReservationId를 바꾼 뒤 CNG를 업데이트하십시오. 블록은 취소·이동·분할 불가, 연장(extend)만 됩니다. 캘린더에 "KST 19:30 최종 체크포인트"를 반복 일정으로 넣으십시오.
srun이 노드를 drain시킬 수 있음
awslabs 운영 가이드 기록: PCS-ready DLAMI(Ubuntu 24.04)에서 slurmd가 기동 직후 systemd에 의해 재시작되면서 prolog 핸드셰이크가 420초 타임아웃 → job 취소 + 노드 drained (Reason=Prolog error). systemd/cgroup-v2 레이스로 템플릿 레벨에서 해결 불가.
→ nodeReady 스테이지의 warmup-srun.sh(버려도 되는 srun -N1 -w $(hostname -s) true)로 prolog 경로를 미리 통과시키고, 그래도 발생하면 scontrol update nodename=<n> state=resume reason=cleared. 125노드 static 기동 시 노드마다 한 번씩 겪을 수 있습니다.
awslabs 기록: 기본 모니터링 스택의 DCGM 4.2.0은 B200까지만 커버합니다. dcgm-exporter는 4.5.2 이상(digest pin)을 쓰십시오. "GPU 메트릭이 안 나온다"의 가장 흔한 원인입니다. DLAMI 내장 DCGM 버전도 AMI Description에서 확인.
MetricsType=metrics/openmetrics + CommunicationParameters=enable_http를 켜면 컨트롤러 6817에서 job/node/partition 메트릭이 나옵니다. PCS 문서 명시: "Anyone with network access to port 6817 can read cluster, job, and node metrics." 클러스터 SG를 신뢰 CIDR로 제한하고 PrivateData는 설정하지 마십시오. awslabs login 노드의 nginx도 /prometheus/·/slurmexporter/를 인증 없이 프록시합니다(/grafana/만 보호). 본운영은 AMP/AMG + SSM 포트포워딩.
- AMI drift — SSM
/latest/참조 금지. AMI ID pin + SNS 알림 구독으로 의도적 갱신 - SMT 비활성은 되돌릴 수 없습니다 — 96 CPU 기준으로 문서·템플릿·컨테이너 CPU limit을 통일. SMT가 필수인 워크로드가 있으면 PCS 밖에서
- MIG를 쓴다면(Slurm 25.11+) — MIG 모드는 GPU 상태라 AMI에 구울 수 없고 매 부팅 boothook에서 켜야 합니다. powered-down 노드에 설정 변경이 전달되지 않고,
CUDA_VISIBLE_DEVICES가 빈 채로 job이 시작될 수 있어 MIG CNG는 static이 문서 권고입니다. B300을 쪼개는 것은 학습용으로 비경제적 → 추론·개발용 별도 CNG로 한정 - 컨트롤러 요금은 노드 0대에도 발생(Medium $4.13/h ≈ $3,000/월). 장기 유휴면 클러스터 삭제를 검토(재생성 시 사이즈 재선택·동시 생성 1개 제약)
- Slurm 버전 EOL — 25.05는 2026-11-30. 클러스터·AMI 양쪽 버전을 분기별로 점검
- lifecycle 스크립트 drift — S3
s3VersionId또는checksum으로 고정. "노드마다 동작이 다르다"의 원인
비용 라인아이템
PCS는 서비스 요금이 있는 관리형입니다. 서울 리전 실가격(AWS 가격 API, 2026-09-14)으로 계산하면 이 규모에서 GPU EC2 비용의 약 0.4%입니다.
| PCS 항목 (서울, USD) | 단가 | 비고 |
|---|---|---|
| 컨트롤러 Medium | $4.1283 / 시간 | Small $0.7381 · Large $8.2906. 노드 0대에도 발생 |
| 노드 관리 Advanced (P·TRN 계열) | $0.810992 / 인스턴스·시간 | GPU 노드 125대 = $101.37/h |
| 노드 관리 Standard (그 외) | $0.101374 / 인스턴스·시간 | login CNG. standalone으로 빼면 0 |
| Accounting 사용료 (Medium) | $1.2418 / 시간 | Small $0.2154 · Large $2.4837 |
| Accounting 스토리지 | $1.0264 / GB·월 | 100 GB ≈ $103/월 |
| 시나리오 | GPU 노드 | login | PCS 요금/시간 | PCS 요금/월 (730h) | GPU EC2 On-Demand/시간 | PCS 비중 |
|---|---|---|---|---|---|---|
| Phase 0 검증 | 2 | 1 | $7.09 | $5,178 | $418 | 1.70% |
| Phase 1 파일럿 | 16 | 2 | $18.55 | $13,541 | $3,347 | 0.55% |
| 본운영 전량 | 125 | 4 | $107.15 | $78,219 | $26,147 | 0.41% |
125노드 계산: Advanced 125 × $0.810992 + Standard 4 × $0.101374 + 컨트롤러 Medium $4.1283 + accounting $1.2418 = $107.15/h. accounting 스토리지 제외. 분 단위 올림 과금.
| 그 외 라인아이템 | 비고 |
|---|---|
GPU 컴퓨트 (p6-b300.48xlarge) | 서울 On-Demand $209.1735/시간. 비용의 대부분. Capacity Block / Savings Plans로 단가 인하 |
| FSx for Lustre / OpenZFS | 용량 × 처리량 등급. 무시할 수 없는 금액 |
| NAT Gateway | 데이터 처리량 과금 — S3/ECR VPC 엔드포인트로 절감. 17 NIC이라도 NAT 트래픽은 primary만 |
| CloudWatch Logs / AMP / AMG | 관측. lifecycle·slurmd 로그 전송량 확인 |
| S3 | 데이터셋 · 체크포인트 아카이브 · 스크립트 |
시간당 $209짜리 노드가 유휴로 도는 것이 가장 큰 낭비이고, PCS에서는 DRAIN된 노드가 자동으로 교체되지 않아 과금되며 남는 것이 두 번째입니다. "DRAIN 상태 N분 초과" CloudWatch 알람을 걸고, AWS Budgets와 Step 7의 팀별 GrpTRES 쿼터로 활용률을 관리하십시오.
참고자료
시작하는 데 가장 빠른 경로 — 이것부터
| 순위 | 자료 | 무엇인가 |
|---|---|---|
| 1 | awslabs/awsome-distributed-ai → architectures/aws-pcs/github.com/awslabs/awsome-distributed-ai/tree/main/architectures/aws-pcs | p6-b300 전용 17-NIC CloudFormation(add-cng-p6-b300.yaml)을 포함한 ML 학습용 PCS 레퍼런스. VPC + FSx + 클러스터 + login/CPU/GPU CNG + Enroot/Pyxis + 모니터링을 deploy-all.yaml 하나로. PoC 첫 배포는 이것으로, 본운영은 FSx를 분리(§4 #6) |
| 2 | AI/ML for AWS PCS 워크숍catalog.workshops.aws/ml-on-pcs/ | 단계별 핸즈온 |
| 3 | PCS User Guidedocs.aws.amazon.com/pcs/latest/userguide/ | 1차 근거. 아래 딥링크 |
| 4 | aws-samples/aws-hpc-recipes → recipes/pcs/ | 공식 레시피: getting_started, enable_efa, observability_for_pcs, dlami_for_pcs_imagebuilder, byo_login, multiuser_demo, terraform_awscc 등 |
| 5 | recipes/net/hpc_large_scale | PCS 요구사항을 만족하는 VPC/서브넷. GPU 서브넷 CIDR만 /20으로 조정 |
PCS User Guide 딥링크 (docs.aws.amazon.com/pcs/latest/userguide/)
| 주제 | 경로 |
|---|---|
| 클러스터 사이즈 | working-with_clusters_size.html |
| VPC·서브넷 요구사항 | working-with_networking_vpc-requirements.html |
| EFA 사용 · 다중 NIC | working-with_networking_efa.html (+ _create-lt, _create-lt-cfn) · working-with_networking_multi-nic.html |
| 하드웨어 토폴로지 / GPU affinity | hardware-topology.html |
| launch template 제약 | working-with_launch-templates_overview.html |
| Capacity Blocks · ODCR · job-level scaling | capacity-blocks.html · capacity-reservations-odcr.html · scaling-job-level.html |
| PCS-ready DLAMI · 커스텀 AMI | working-with_ami_pcs-ready-dlami.html · working-with_ami_custom.html |
| Node lifecycle actions | cng-node-lifecycle-actions.html (+ -configure, -examples, -aws-scripts) |
| Custom Slurm settings (허용 목록) | slurm-custom-settings.html · slurm-custom-settings-cluster.html / -queue.html / -cng.html |
| GRES · MIG · accounting · metrics | gres-custom-settings.html · mig-configuration.html · slurm-accounting.html · slurm-metrics.html |
scontrol reboot · 버전 정책 · 업그레이드 | slurm-reboot.html · working-with_slurm-versions.html · working-with_clusters_version_update.html |
| login 노드 (CNG / standalone) | working-with_login-nodes.html · _standalone |
| 트러블슈팅 | troubleshooting-compute-node-bootstrap.html · troubleshooting-invalid-registration.html |
| 쿼터 | service-endpoints-quotas.html |
도구 · 벤치마크
- GPU Cluster Health Check 스위트:
awslabs/awsome-distributed-ai/validation/gpu-cluster-healthcheck(lightweight / intensive, prolog 래퍼 포함) - NCCL tests 컨테이너:
public.ecr.aws#hpc-cloud/nccl-tests·micro-benchmarks/nccl-tests/slurm/nccl-tests-container.sbatch - PyTorch FSDP 예제:
awslabs/awsome-distributed-ai/examples/training/fsdp - 검증 매트릭스:
architectures/aws-pcs/tests/(compute · hpc-efa · gpu-healthcheck · training · storage · multi-user · iam) - NVIDIA Xid 에러 코드:
docs.nvidia.com/deploy/xid-errors· DCGM diag 레벨:docs.nvidia.com/datacenter/dcgm
블로그
- AWS HPC Blog · Announcing Capacity Blocks support for AWS Parallel Computing Service
- AWS HPC Blog · The complete picture: unified monitoring for AWS PCS (AMP/AMG + ADOT + DCGM/EFA/Slurm exporter)
- AWS HPC Blog · Announcing expanded support for custom Slurm settings in AWS PCS
- AWS HPC Blog · Part 1/2: Managing Large-Scale LLM Training with AWS ParallelCluster — PCS는 아니지만 운영 관점(파티션·QoS·Lustre·OOM)이 그대로 적용됨. ⚠ 그 글의
UnkillableStepTimeout해석과AdministratorAccessIAM은 따르지 마십시오
미확정 · AWS 확인 필요 항목
| # | 항목 | 영향 | 언제 |
|---|---|---|---|
| 1 | 서울 p6-b300 Capacity Block 최대 블록 크기 (64대인지 그 이하인지) | 125노드를 몇 개 블록/CNG로 나눌지 | 착수 전 최우선 |
| 2 | 서울에서 p6-b300 가용 AZ | 서브넷 · FSx · placement group 배치가 전부 종속 | 착수 전 |
| 3 | CNG당 최대 인스턴스 수 | ODCR 경로에서 125노드 단일 CNG 가능 여부 | 착수 전 |
| 4 | PCS에서 InterfaceType: efa-only 동작 여부 | 통하면 노드당 IP 17 → 1. 서브넷은 17 기준으로 잡되 PoC에서 실측 | Step 5·9 |
| 5 | PCS의 DRAIN/장애 노드 처리 — static CNG에서 수동 종료 시 자동 재launch 여부, DRAIN 노드 자동 교체 유무 | Step 8 복구 경로(b)의 전제 | Step 9 리허설 |
| 6 | p6-b300 NUMA 도메인 수 / Slurm Sockets 권장값 | 25.11 사용 시 필수(틀리면 INVALID_REG). 26.05면 불필요 | Step 6 |
| 7 | p6-b300 GPUDirect Storage(FSx Lustre over EFA) 지원 여부 | 스토리지 대역폭 설계 | Step 2 이후 |
| 8 | p6-b300 다중 노드 NCCL 기대 대역폭 | 성능 합격 판정 기준. 공개치는 p6-b200 377 GB/s뿐 | Step 9 |
| 9 | EC2 P 인스턴스 vCPU 쿼터 증설 리드타임 (ODCR 경로만) | 일정의 첫 의존성 | Step 0 |
| 10 | PCS 서울 리전 100노드+ 실사용 사례 | 고객 레퍼런스 요청 대응 | — |
| 11 | Capacity Block 합계 256대 한도의 적용 단위 (계정 vs 조직) | 다른 팀·계정의 CB와 합산되는지 | Step 0 |