네. 현재 정리한 validation.openai.com/b300=true label과 GPU Operator 환경을 기준으로 하면 아래 YAML이면 충분합니다.
apiVersion: v1
kind: Pod
metadata:
name: b300-gpu-1-smoke
namespace: gpu-validation
labels:
app: b300-gpu-smoke
stage: stage6-preflight
spec:
restartPolicy: Never
# Stage6 canonical profile:
# STAGE6_GPU_NODE_SELECTOR_KEY=validation.openai.com/b300
# STAGE6_GPU_NODE_SELECTOR_VALUE=true
nodeSelector:
validation.openai.com/b300: "true"
# GPU node에 아래 taint를 적용한 경우 필요:
# nvidia.com/gpu=true:NoSchedule
tolerations:
- key: nvidia.com/gpu
operator: Equal
value: "true"
effect: NoSchedule
containers:
- name: cuda-smoke
image: nvcr.io/nvidia/cuda:13.0.2-base-ubuntu24.04
imagePullPolicy: IfNotPresent
command:
- /bin/bash
- -c
- |
set -euo pipefail
echo "========================================"
echo " Stage6 Preflight - 1 GPU Smoke Test"
echo "========================================"
echo
echo "[1] Pod / Node"
echo "HOSTNAME=${HOSTNAME}"
echo "NODE_NAME=${NODE_NAME}"
echo
echo "[2] NVIDIA_VISIBLE_DEVICES"
echo "${NVIDIA_VISIBLE_DEVICES:-<unset>}"
echo
echo "[3] nvidia-smi"
nvidia-smi
echo
echo "[4] GPU list"
nvidia-smi -L
echo
echo "[5] Allocated GPU count"
GPU_COUNT="$(nvidia-smi --query-gpu=uuid \
--format=csv,noheader | wc -l)"
echo "GPU_COUNT=${GPU_COUNT}"
if [ "${GPU_COUNT}" -ne 1 ]; then
echo "FAIL: expected exactly 1 GPU, got ${GPU_COUNT}"
exit 1
fi
echo
echo "[6] GPU properties"
nvidia-smi \
--query-gpu=index,name,uuid,driver_version,memory.total,\
temperature.gpu,power.draw \
--format=csv
echo
echo "========================================"
echo " PASS: exactly one GPU is visible"
echo "========================================"
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
resources:
requests:
cpu: "1"
memory: 1Gi
nvidia.com/gpu: 1
limits:
cpu: "1"
memory: 1Gi
nvidia.com/gpu: 1
예를 들어 stage6_gpu_1_smoke.yaml로 저장한 뒤 먼저 namespace와 node를 확인합니다.
kubectl create namespace gpu-validation
kubectl get nodes -l validation.openai.com/b300=true \
-o custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\\.com/gpu
여기서 기대하는 것은 대략:
NAME GPU
b300-gpu-01 8
입니다. 그다음 smoke test를 실행합니다.
kubectl apply -f stage6_gpu_1_smoke.yaml
kubectl get pod -n gpu-validation \
b300-gpu-1-smoke -o wide
kubectl logs -n gpu-validation \
b300-gpu-1-smoke
정상이라면 핵심적으로:
[3] nvidia-smi
...
[4] GPU list
GPU 0: NVIDIA B300 ...
[5] Allocated GPU count
GPU_COUNT=1
PASS: exactly one GPU is visible
가 나와야 합니다. 호스트에 GPU가 8장 있더라도 이 Pod에서는 정확히 1장만 보여야 한다는 것이 이 시험의 핵심입니다.
Pod가 Pending이면 바로 다음을 보세요.
kubectl describe pod -n gpu-validation \
b300-gpu-1-smoke
특히 Events에서 Insufficient nvidia.com/gpu, node selector mismatch, taint/toleration 문제를 확인하면 됩니다.
시험 후에는:
kubectl delete -f stage6_gpu_1_smoke.yaml
로 정리하면 됩니다.
한 가지 추가로, 이 테스트는 Device Plugin → container runtime → GPU device injection smoke test이지 CUDA 연산 검증까지 하는 것은 아닙니다. 이게 PASS하면 다음 단계에서 GPU 8장 Pod + nvidia-smi topo -m + CUDA compute smoke를 묶은 YAML을 실행하고, 그 다음 기존 6c → 6a NCCL로 넘어가는 흐름이 가장 깔끔합니다.
===
네. 이번에는 8 GPU 할당 검증 + nvidia-smi topo -m + GPU별 CUDA 실제 연산을 한 Pod에서 수행하도록 만들면 좋습니다.
단순 nvidia-smi만 보는 게 아니라 CUDA/PyTorch로 8개 GPU 각각에 실제 matrix multiplication을 수행하게 하겠습니다. 이 테스트가 PASS한 뒤 Stage6c → Stage6a NCCL로 넘어가면 됩니다.
apiVersion: v1
kind: Pod
metadata:
name: b300-gpu-8-smoke
namespace: gpu-validation
labels:
app: b300-gpu-smoke
stage: stage6-preflight
spec:
restartPolicy: Never
# Stage6 canonical profile:
# STAGE6_GPU_NODE_SELECTOR_KEY=validation.openai.com/b300
# STAGE6_GPU_NODE_SELECTOR_VALUE=true
nodeSelector:
validation.openai.com/b300: "true"
# GPU node에 아래 taint를 적용한 경우:
# nvidia.com/gpu=true:NoSchedule
tolerations:
- key: nvidia.com/gpu
operator: Equal
value: "true"
effect: NoSchedule
containers:
- name: gpu-smoke
# PyTorch + CUDA가 포함된 이미지.
# 실제 운영에서는 내부 registry에 검증한 버전을 pinning하는 것을 권장.
image: nvcr.io/nvidia/pytorch:24.08-py3
imagePullPolicy: IfNotPresent
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
command:
- /bin/bash
- -c
- |
set -euo pipefail
echo "================================================="
echo " Stage6 Preflight - 8 GPU / Topology / CUDA Smoke"
echo "================================================="
echo
echo "-------------------------------------------------"
echo "[1] Pod / Node"
echo "-------------------------------------------------"
echo "HOSTNAME=${HOSTNAME}"
echo "NODE_NAME=${NODE_NAME}"
echo
echo "-------------------------------------------------"
echo "[2] NVIDIA_VISIBLE_DEVICES"
echo "-------------------------------------------------"
echo "${NVIDIA_VISIBLE_DEVICES:-<unset>}"
echo
echo "-------------------------------------------------"
echo "[3] nvidia-smi"
echo "-------------------------------------------------"
nvidia-smi
echo
echo "-------------------------------------------------"
echo "[4] GPU list"
echo "-------------------------------------------------"
nvidia-smi -L
GPU_COUNT="$(nvidia-smi \
--query-gpu=uuid \
--format=csv,noheader | wc -l)"
echo
echo "Detected GPU count: ${GPU_COUNT}"
if [ "${GPU_COUNT}" -ne 8 ]; then
echo
echo "FAIL: expected exactly 8 GPUs"
echo " detected=${GPU_COUNT}"
exit 1
fi
echo
echo "PASS: exactly 8 GPUs are visible"
echo
echo "-------------------------------------------------"
echo "[5] GPU properties"
echo "-------------------------------------------------"
nvidia-smi \
--query-gpu=index,name,uuid,driver_version,memory.total,\
temperature.gpu,power.draw \
--format=csv
echo
echo "-------------------------------------------------"
echo "[6] GPU topology"
echo "-------------------------------------------------"
nvidia-smi topo -m
echo
echo "-------------------------------------------------"
echo "[7] NVLink status"
echo "-------------------------------------------------"
# 지원되지 않는 driver/platform 조합에서도
# 전체 smoke test를 바로 중단시키지는 않음.
nvidia-smi nvlink --status || true
echo
echo "-------------------------------------------------"
echo "[8] PyTorch / CUDA environment"
echo "-------------------------------------------------"
python3 - <<'PY'
import torch
print("PyTorch version :", torch.__version__)
print("CUDA version :", torch.version.cuda)
print("CUDA available :", torch.cuda.is_available())
print("GPU count :", torch.cuda.device_count())
if not torch.cuda.is_available():
raise SystemExit(
"FAIL: torch.cuda.is_available() == False"
)
if torch.cuda.device_count() != 8:
raise SystemExit(
f"FAIL: expected 8 CUDA devices, "
f"got {torch.cuda.device_count()}"
)
print()
print("CUDA device list")
for i in range(torch.cuda.device_count()):
p = torch.cuda.get_device_properties(i)
print(
f"GPU {i}: "
f"{p.name}, "
f"memory={p.total_memory / 1024**3:.1f} GiB, "
f"capability={p.major}.{p.minor}"
)
PY
echo
echo "-------------------------------------------------"
echo "[9] CUDA compute smoke - all 8 GPUs"
echo "-------------------------------------------------"
python3 - <<'PY'
import sys
import time
import torch
expected_gpus = 8
if not torch.cuda.is_available():
print("FAIL: CUDA unavailable")
sys.exit(1)
if torch.cuda.device_count() != expected_gpus:
print(
f"FAIL: expected {expected_gpus} GPUs, "
f"got {torch.cuda.device_count()}"
)
sys.exit(1)
failures = []
# Smoke test 목적이므로 너무 큰 matrix를 사용하지 않는다.
# Stage1 stress/burn test의 대체가 아님.
matrix_size = 4096
print(
f"Matrix multiplication: "
f"{matrix_size} x {matrix_size}"
)
print()
for gpu in range(expected_gpus):
try:
torch.cuda.set_device(gpu)
device = torch.device(f"cuda:{gpu}")
# BF16은 B300 inference 환경에서
# 기본 CUDA compute sanity 확인용으로 사용.
a = torch.randn(
matrix_size,
matrix_size,
device=device,
dtype=torch.bfloat16,
)
b = torch.randn(
matrix_size,
matrix_size,
device=device,
dtype=torch.bfloat16,
)
# 초기 CUDA context / kernel 준비
_ = torch.matmul(a, b)
torch.cuda.synchronize(device)
start = time.perf_counter()
c = torch.matmul(a, b)
torch.cuda.synchronize(device)
elapsed = time.perf_counter() - start
if not torch.isfinite(c).all().item():
raise RuntimeError(
"non-finite value detected"
)
print(
f"GPU {gpu}: PASS "
f"time={elapsed:.4f}s "
f"result_mean={c.float().mean().item():.6f}"
)
del a, b, c
torch.cuda.empty_cache()
except Exception as exc:
print(
f"GPU {gpu}: FAIL: {exc}"
)
failures.append((gpu, str(exc)))
print()
print("-----------------------------------------")
if failures:
print("CUDA COMPUTE SMOKE: FAIL")
for gpu, reason in failures:
print(
f" GPU {gpu}: {reason}"
)
sys.exit(1)
print(
"CUDA COMPUTE SMOKE: "
"PASS - all 8 GPUs"
)
PY
echo
echo "-------------------------------------------------"
echo "[10] Final GPU state"
echo "-------------------------------------------------"
nvidia-smi \
--query-gpu=index,name,temperature.gpu,power.draw,\
memory.used,memory.total \
--format=csv
echo
echo "================================================="
echo " PASS: Stage6 8-GPU preflight smoke completed"
echo "================================================="
resources:
requests:
cpu: "8"
memory: 16Gi
nvidia.com/gpu: 8
limits:
cpu: "8"
memory: 16Gi
nvidia.com/gpu: 8
파일명을 예를 들어 stage6_gpu_8_smoke.yaml로 두면 됩니다.
먼저 GPU allocatable을 확인합니다.
kubectl get node b300-gpu-01 \
-o custom-columns=\
NAME:.metadata.name,\
GPU-CAPACITY:.status.capacity.nvidia\\.com/gpu,\
GPU-ALLOCATABLE:.status.allocatable.nvidia\\.com/gpu
반드시 대략:
NAME GPU-CAPACITY GPU-ALLOCATABLE
b300-gpu-01 8 8
이어야 합니다.
그다음:
kubectl apply -f stage6_gpu_8_smoke.yaml
kubectl get pod \
-n gpu-validation \
b300-gpu-8-smoke \
-o wide
실시간으로 보는 편이 편합니다.
kubectl logs \
-n gpu-validation \
-f b300-gpu-8-smoke
성공 시 핵심적으로 다음 결과가 나와야 합니다.
Detected GPU count: 8
PASS: exactly 8 GPUs are visible
GPU topology
...
nvidia-smi topo -m 결과
...
CUDA available : True
GPU count : 8
CUDA compute smoke - all 8 GPUs
GPU 0: PASS
GPU 1: PASS
GPU 2: PASS
GPU 3: PASS
GPU 4: PASS
GPU 5: PASS
GPU 6: PASS
GPU 7: PASS
CUDA COMPUTE SMOKE: PASS - all 8 GPUs
PASS: Stage6 8-GPU preflight smoke completed
여기서 nvidia-smi topo -m은 단순히 명령 성공만 보지 말고 8 GPU가 모두 나타나는지와 GPU 간 NVLink/NVSwitch topology가 예상대로 노출되는지를 확인하는 게 중요합니다. 이 YAML의 CUDA compute는 GPU마다 독립적으로 연산하므로 GPU 간 통신 검증은 아닙니다. GPU 간 collective communication은 바로 다음 Stage6a NCCL에서 검증하는 게 맞습니다.
따라서 현재 Stage6 진입 순서를 조금 더 명확하게 만들면:
GPU Operator 설치
↓
nvidia.com/gpu = 8
↓
1-GPU Smoke
↓
8-GPU Smoke
├─ GPU allocation = 8
├─ nvidia-smi
├─ topo -m
├─ NVLink visibility
└─ CUDA compute GPU0~7
↓
Stage6c
GPU Operator / topology 정식 검사
↓
Stage6a
NCCL TP8 collective
↓
Stage6b
Network
↓
Stage6e
AIStor
↓
Stage6k
vLLM
로 가져가면 됩니다.
참고로 FP8/FP4 smoke는 이 YAML에 일부러 넣지 않았습니다. 여기서는 K8s device injection + CUDA 기본 연산까지만 확인하고, FP8/FP4는 Stage1에서 이미 실제 연산 검증을 했으므로 Stage6에서는 별도의 짧은 container precision sanity로 분리하는 편이 장애 원인을 구분하기 좋습니다.