GPU-Live/nccl_test/simple-test/template.yaml

153 lines
4.7 KiB
YAML

apiVersion: v1
kind: ConfigMap
metadata:
name: nccl-scripts
data:
run.sh: |
#!/usr/bin/env bash
set -ex
# 현재 실행 시작 시 타임스탬프 저장
START_TIME=$(date +%s)
# ----- RDMA/IB 강제 -----
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NET,IB
#export NCCL_NET=IB
#export NCCL_IB_DISABLE=0
export NCCL_SOCKET_IFNAME="${NCCL_SOCKET_IFNAME:-net1}" # HostDeviceNetwork로 붙인 NIC 이름
export NCCL_IB_HCA="mlx5_0,mlx5_1,mlx5_2,mlx5_8,mlx5_9,mlx5_5,mlx5_6,mlx5_7"
export NCCL_NET_GDR_LEVEL=2
# (RoCE 환경에 따라 필요 시) export NCCL_IB_GID_INDEX=3
# 프로세스별 로그 파일 경로 (노드/프로세스마다 별도 파일)
export NCCL_DEBUG_FILE="/tmp/nccl-%h-%p.log"
# ----- 학습 실행 (각 파드가 1개 프로세스씩 구동) -----
echo "[RUN] RANK=$RANK on $(hostname)"
torchrun \
--nnodes=2 \
--nproc_per_node=8 \
--rdzv_backend=c10d \
--node_rank=0 \
--rdzv_endpoint=nccl-0.nccl:23456 \
/workspace/train_nccl.py 2>&1 | tee /tmp/nccl-aggregate.log
# ----- RDMA 사용 여부 집계 -----
# 새로 생성된 로그 목록 가져오기: START_TIME 이후 생성된 파일만
new_logs=$(find /tmp -name "nccl-nccl-*.log" -type f -newermt "@${START_TIME}")
total=0; ok=0
for f in $new_logs; do
[[ -f "$f" ]] || continue
total=$((total+1))
if rdma_line=$(grep -E "Channel .*GDRDMA" "$f"); then
echo "[OK] RDMA: $rdma_line"
ok=$((ok+1))
fi
done
echo "[RDMA-CHECK] used IB on $ok / $total local ranks (processes) in $(hostname)"
# 모든 랭크가 IB를 썼는지(파드 단위) 판단: 로컬 프로세스 수와 비교
if [[ "$ok" -eq 8 ]]; then
echo "[RDMA-CHECK] ✅ RDMA path OK for all local GPUs"
exit 0
else
echo "[RDMA-CHECK] ❌ RDMA path NOT used by all local GPUs"
echo "---- NCCL NET/IB related lines ----"
grep -h "NET/" /tmp/nccl-*.log || true
exit 1
fi
train_nccl.py: |
import os
import torch
import torch.distributed as dist
def main():
dist.init_process_group("nccl")
local_rank = int(os.environ["LOCAL_RANK"])
torch.cuda.set_device(local_rank)
print(f"Rank {dist.get_rank()} initialized on GPU {local_rank}")
x = torch.ones(10).cuda()
dist.all_reduce(x)
print(f"Rank {dist.get_rank()} result: {x[0].item()}")
if __name__ == "__main__":
main()
---
apiVersion: v1
kind: Service
metadata:
name: nccl
labels: { app: nccl }
spec:
clusterIP: None # Headless
selector: { app: nccl }
ports:
- name: rdv
port: 23456
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nccl
spec:
serviceName: nccl
replicas: 2 # >=2 노드에서 스케줄되도록 노드 리소스 준비 필요
selector:
matchLabels: { app: nccl }
template:
metadata:
labels: { app: nccl }
annotations:
k8s.v1.cni.cncf.io/networks: hostdevice-net # HostDeviceNetwork (RDMA)
spec:
# hostNetwork: true
# dnsPolicy: ClusterFirstWithHostNet
# RDMA 장치나 /dev/infiniband 노출이 안 보이면 네트워크 오퍼레이터의 RDMA 플러그인 구성을 확인하세요.
# (환경에 따라 RDMA Shared Device Plugin이 필요할 수 있음)
containers:
- name: worker
image: nvcr.io/nvidia/pytorch:24.10-py3
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
capabilities:
add:
- IPC_LOCK
- NET_ADMIN
# capabilities: { add: ["IPC_LOCK"] }
command: [ "bash", "-lc", "cp /config_scripts/* /workspace/ && chmod +x /workspace/run.sh && sleep infinity" ]
env:
# --- (선택) 특정 GPU만 사용하려면 아래 값을 물리 인덱스로 설정 (예: "2") ---
# - name: CUDA_VISIBLE_DEVICES_OVERRIDE
# value: "2"
# RDMA 관련 기본값은 run.sh에서 설정
resources:
limits:
nvidia.com/gpu: "8"
nvidia.com/hostdev: "8" # SR-IOV Device Plugin이 광고한 RDMA NIC 리소스
requests:
nvidia.com/gpu: "8"
nvidia.com/hostdev: "8"
volumeMounts:
- name: scripts
mountPath: /config_scripts
- name: shared-memory
mountPath: /dev/shm
volumes:
- name: scripts
configMap:
name: nccl-scripts
defaultMode: 0755
- name: shared-memory
emptyDir:
medium: Memory
sizeLimit: 118541097369600m