Self-Hosted Cluster for LLM Training
Kubernetes, Slurm, InfiniBand/RoCEv2, distributed storage, GPU orchestration. Updated in April 2026.
Overview
Training LLMs at scale requires more than GPUs — it requires a cluster with high-performance networking, distributed storage, and efficient orchestration.
This document covers how to build and operate a self-hosted cluster for LLM training, from hardware to software configuration.
Cluster Topology
Typical architecture
──────────────────────────────────────────────────────────────┐
│ LLM Training Cluster │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node N │ │
│ │ 4× A100 │ │ 4× A100 │ │ 4× A100 │ │
│ │ 2× CPU │ │ 2× CPU │ │ 2× CPU │ │
│ │ 512GB RAM │ │ 512GB RAM │ │ 512GB RAM │ │
│ ──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Switch IB │ ← InfiniBand NDR/XDR │
│ │ (32/64 port)│ 200/400 Gbps │
│ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Storage │ ← Lustre / Ceph / WekaIO │
│ │ (100TB+) │ Parallel filesystem │
│ └─────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ Head Node │ ← Kubernetes master / Slurm controller │
│ │ (CPU only) │ │
│ └─────────────┘ │
└──────────────────────────────────────────────────────────────┘Networking
InfiniBand vs Ethernet
| Technology | Speed | Latency | Cost | Use in LLM |
|---|---|---|---|---|
| InfiniBand NDR | 200 Gbps | ~0.5µs | High | Gold standard for training |
| InfiniBand XDR | 400 Gbps | ~0.3µs | Very high | State-of-art |
| RoCEv2 (RDMA over Ethernet) | 100–400 Gbps | ~2–5µs | Medium | Viable alternative |
| Ethernet 100GbE | 100 Gbps | ~10µs | Low | Inference only |
For distributed LLM training: InfiniBand is essential. The all-reduce (gradient synchronization across GPUs) dominates training time, and InfiniBand latency is 10–20× lower than Ethernet.
Network topology
Fat-Tree topology (standard for GPU clusters):
GPU Nodes Spine Switches Leaf Switches
┌──┐ ┌──┐ ┌── ┌──┐ ┌──┐ ┌──┐
│N1│─│N2│──────────│S1│─│S2│────────────│L1│─│L2│
└──┘ └── └──┘ └── └──┘ └──┘
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
│N3│─│N4│──────────│S3│─│S4│────────────│L3│─│L4│
└──┘ └──┘ └──┘ └──┘ └── └──┘
Bisection bandwidth: non-blocking (each node has full bandwidth)Rule of thumb: For a cluster of 16–64 GPUs, use 1 InfiniBand switch with 32 ports. For 64–256 GPUs, a fat-tree with 2 levels of switches.
Storage
Requirements
LLM training needs storage with:
- High throughput: 10+ GB/s to load datasets
- Low latency: for frequent checkpointing
- Parallel I/O: multiple nodes reading/writing simultaneously
- Capacity: 50–200TB for datasets + checkpoints
Storage options
| System | Type | Throughput | Complexity | Cost |
|---|---|---|---|---|
| Lustre | Parallel filesystem | 100+ GB/s | High | High |
| WekaIO | Parallel filesystem | 50+ GB/s | Medium | High |
| Ceph | Distributed object/block | 10–30 GB/s | High | Medium |
| NFS | Network filesystem | 1–5 GB/s | Low | Low |
| Local SSD | NVMe on each node | 3–7 GB/s per node | Low | Medium |
Recommendation:
- Small cluster (≤ 16 GPUs): NFS + local SSD for checkpoints
- Medium cluster (16–64 GPUs): WekaIO or Ceph
- Large cluster (64+ GPUs): Lustre
Storage structure
/storage/
├── datasets/ ← Training datasets (read-only for workers)
│ ├── code/
│ ├── text/
│ └── multimodal/
├── checkpoints/ ← Training checkpoints (write-heavy)
│ ├── run_001/
│ │ ├── step_1000/
│ │ ├── step_2000/
│ │ └── ...
│ └── run_002/
── logs/ ← Training logs
├── models/ ← Final exported models
└── scratch/ ← Temporary data (per job)Orchestration
Kubernetes vs Slurm
| Factor | Kubernetes | Slurm |
|---|---|---|
| Learning curve | High | Medium |
| Flexibility | High (any workload) | Medium (HPC-focused) |
| GPU scheduling | Good (device plugin) | Excellent (native) |
| Networking | CNI (Calico, Cilium) | InfiniBand native |
| Storage | CSI drivers | Lustre/NFS native |
| ML community | Growing | Established |
| Multi-tenant | Excellent | Good |
| ML tooling | Kubeflow, Volcano | PyTorch + MPI native |
Recommendation:
- If you already have a Kubernetes team: use Kubernetes with Volcano (batch scheduler)
- If you are new to orchestration: Slurm is simpler for ML
- If you need multi-tenant: Kubernetes
Kubernetes for ML
# Example of a training job on Kubernetes
apiVersion: batch/v1
kind: Job
metadata:
name: llm-training-run-001
spec:
parallelism: 8
completions: 8
template:
spec:
containers:
- name: trainer
image: pytorch/pytorch:2.3.0-cuda12.1
command: ["python", "train.py", "--config", "llm_7b.yaml"]
resources:
limits:
nvidia.com/gpu: 1
memory: 128Gi
cpu: "32"
volumeMounts:
- name: datasets
mountPath: /storage/datasets
- name: checkpoints
mountPath: /storage/checkpoints
volumes:
- name: datasets
persistentVolumeClaim:
claimName: datasets-pvc
- name: checkpoints
persistentVolumeClaim:
claimName: checkpoints-pvc
restartPolicy: NeverKubernetes tools for ML:
- Volcano — batch scheduler with gang scheduling (all pods come up together)
- Kubeflow Training Operator — PyTorchJob, MPIJob, XGBoostJob
- Kueue — queueing and quota management
- NVIDIA GPU Operator — drivers, device plugin, MIG
Slurm for ML
#!/bin/bash
#SBATCH --job-name=llm-training
#SBATCH --nodes=8
#SBATCH --gpus-per-node=4
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=32
#SBATCH --mem=512G
#SBATCH --time=72:00:00
#SBATCH --partition=gpu
srun python train.py --config llm_7b.yamlAdvantages of Slurm:
- Simple to configure for ML
- Native InfiniBand (MVAPICH2, OpenMPI)
- Native checkpoint/restart
- Established HPC community
GPU Provisioning
Configuration per node
| Component | Specification |
|---|---|
| GPUs | 4× NVIDIA A100 80GB or H100 80GB |
| CPU | 2× AMD EPYC 7763 (64 cores each) or Intel Xeon Platinum |
| RAM | 512GB–1TB DDR5 |
| Local storage | 2× NVMe 4TB (RAID 1 for OS, RAID 0 for scratch) |
| Network | 1× InfiniBand NDR (200 Gbps) + 1× Ethernet 25GbE (management) |
| PSU | 2× 2000W (redundant) |
Pre-built servers
| Model | GPUs | Approx. price |
|---|---|---|
| Dell PowerEdge XE9680 | 8× H100 | $350K |
| Supermicro AS-4125GO | 8× H100 | $300K |
| Gigabyte G493-Z83 | 8× H100 | $280K |
| Lambda Hyperplane | 8× H100 | $320K |
| NVIDIA DGX H100 | 8× H100 | $400K |
For 16 GPUs (4 nodes): ~$1.2–1.6M in hardware.
Software Configuration
Software stack
Level 1: Operating system
→ Ubuntu 22.04 LTS or Rocky Linux 9
Level 2: Drivers and runtime
→ NVIDIA Driver 550+
→ CUDA 12.4
→ cuDNN 9.x
→ NCCL 2.20+ (GPU-GPU communication)
Level 3: Networking
→ OFED (OpenFabrics Enterprise Distribution)
→ InfiniBand drivers
→ UCX (Unified Communication X)
Level 4: Storage
→ Lustre client or WekaIO agent
→ NFS client
Level 5: Orchestration
→ Kubernetes + Volcano or Slurm
Level 6: ML Framework
→ PyTorch 2.3+
→ DeepSpeed / Megatron-LM / FSDP
Level 7: Monitoring
→ Prometheus + Grafana
→ DCGM (NVIDIA Data Center GPU Manager)
→ Slurm accounting or Kubernetes metricsNCCL — GPU Communication
NCCL (NVIDIA Collective Communications Library) is the heart of distributed training:
import torch.distributed as dist
# Initialize process group with NCCL backend
dist.init_process_group(backend="nccl")
# All-reduce: sum gradients across all GPUs
torch.distributed.all_reduce(tensor, op=dist.ReduceOp.SUM)Performance configuration:
# Environment variables to optimize NCCL
export NCCL_PROTO=simple # simple or ll (low latency)
export NCCL_ALGO=Ring # Ring, Tree, or CollNet
export NCCL_SOCKET_IFNAME=eth0
export NCCL_IB_DISABLE=0 # Use InfiniBand
export NCCL_IB_HCA=mlx5 # HCA driver
export NCCL_IB_TC=106 # Traffic classMonitoring and Observability
Hardware metrics
| Metric | Tool | Alert if |
|---|---|---|
| GPU utilization | DCGM, nvtop | < 80% (inefficiency) |
| GPU memory usage | DCGM | > 95% (OOM risk) |
| GPU temperature | DCGM | > 85°C |
| GPU power | DCGM | > TDP (thermal throttling) |
| NVLink bandwidth | DCGM | < expected |
| InfiniBand errors | ibstat | > 0 |
| Disk I/O | iostat | < 50% of capacity |
Training metrics
| Metric | What it indicates |
|---|---|
| Loss curve | Model convergence |
| Gradient norm | Exploding/vanishing gradients |
| Throughput (tokens/sec) | Training efficiency |
| MFU (Model FLOPS Utilization) | % of theoretical peak achieved |
MFU target: > 40% for A100, > 50% for H100. If MFU < 30%, there is a bottleneck problem (I/O, networking, or code).
For Kode
Recommended minimum cluster
To train Kode (7–30B model):
| Configuration | Specification | Approx. cost |
|---|---|---|
| Minimum | 2 nodes, 4× A100 80GB each, 200Gb IB | $250K |
| Recommended | 4 nodes, 4× A100 80GB each, 200Gb IB | $500K |
| Ideal | 8 nodes, 8× H100 80GB each, 400Gb IB | $2.5M |
Step-by-step setup
Week 1–2: Physical infrastructure
→ Install racks, cables, InfiniBand switches
→ Configure storage (NFS or WekaIO)
→ Install OS on all nodes
Week 3: Base software
→ NVIDIA drivers, CUDA, cuDNN
→ NCCL, UCX, InfiniBand stack
→ Test GPU-GPU communication (NCCL tests)
Week 4: Orchestration
→ Install Kubernetes + Volcano or Slurm
→ Configure GPU scheduling
→ Test distributed job
Week 5: ML stack
→ PyTorch, DeepSpeed/FSDP, Megatron-LM
→ Configure monitoring (DCGM, Prometheus)
→ Test training of a small model
Week 6+: Optimization
→ Tuning of NCCL, I/O, parallelism
→ Throughput benchmark
→ Document proceduresAlternative: Hybrid cloud
If the budget does not allow an on-premise cluster:
Phase 1: Cloud for training (Lambda Labs / CoreWeave)
→ Rent 8–16 A100 per week
→ Train the model
→ Cost: $5K–$15K per training run
Phase 2: On-premise for inference
→ 2× RTX 4090 for serving
→ Cost: $5K in hardware
Phase 3: Migrate training to on-premise when justified
→ When cloud cost > on-premise cost within 12 monthsReferences
| Resource | Description |
|---|---|
| NVIDIA NCCL docs | Official NCCL documentation |
| Slurm docs | Slurm documentation |
| Kubernetes GPU scheduling | NVIDIA docs + K8s device plugin |
| Lambda Labs | GPU cloud provider |
| CoreWeave | Alternative GPU cloud provider |
| MLPerf Training | Training performance benchmarks |