Plánování úloh pro AI clustery: SLURM, Kubernetes, Ray a kdy nepotřebujete ani jedno

Scheduler rozhoduje o tom, která úloha poběží na kterých GPU, kdy a na čí účet. Bez něj se sdílený cluster zvrhne v to, že si lidé na Slacku píšou, jestli zrovna někdo nepoužívá node 3. Se špatným schedulerem strávíte víc inženýrských hodin nad YAMLem než nad samotnými modely.

Tento článek porovnává schedulery, po kterých lidé reálně sahají — SLURM, Kubernetes (s Kueue nebo Volcano), Ray a KubeRay a komerční řešení Run:ai a Determined — a nezastírá ani případ, kdy je správnou odpovědí „nic, stačí SSH“. Čtenář už má za sebou K01, K02 a K03 a nyní se rozhoduje, co nad cluster o 1–32 uzlech postavit.

Co scheduler vlastně dělá

Tři úkoly, zhruba v pořadí podle obtížnosti: umístit práci na volné zdroje, zařadit do fronty práci, která se zatím nevejde, a koordinovat víceuzlové úlohy — distribuovaný trénink potřebuje, aby všech N ranků odstartovalo naráz (gang scheduling), protože v PyTorchi dist.barrier() blokuje donekonečna, pokud se jeden rank nikdy neukáže (viz K06).

Cokoli nad rámec clusteru pro jediný tým navíc potřebuje multi-tenantní kvóty s půjčováním, slábnoucí fair-share mezi týmy, preempci a pořádné účtování GPU (aby úloha viděla správně nastavené CUDA_VISIBLE_DEVICES ). Všechny schedulery níže zvládají první tři body. Liší se v tom druhém seznamu a v tom, jakou práci u Vás předpokládají.

Zásadní dělicí čára: dávkové úlohy vs. dlouho běžící služby

Tohle je vůbec nejdůležitější rozlišení. Dávkové úlohy trénují osm hodin a skončí, proženou sweep 200 krátkých úloh nebo přes noc zpracují dataset — začátek, konec, výsledek, nic neodpovídá na HTTP. Dlouho běžící služby jsou vLLM endpoint obsluhující inferenci 24/7, databáze scene memory nebo monitorovací stack — mají běžet pořád a po pádu se restartovat.

SLURM vznikl pro dávky. Kubernetes vzniklo pro dlouho běžící služby. Všechno ostatní je jedno z těch dvou natahované na tu druhou polovinu.

Workload SLURM Kubernetes
Osmihodinový trénink Nativně Potřebuje Kueue nebo Volcano
Sweep 200 úloh přes hyperparametry Nativně Neohrabané
vLLM inferenční endpoint 24/7 Neohrabané Nativně
Mix: trénink + inference + nástroje Bolestivé Nativně (s Kueue)
Víceuzlový distribuovaný trénink Nativně (gang) Potřebuje gang plugin
Automatický restart spadlých služeb Ne Nativně

Pokud Váš cluster dělá jen jednu z těch věcí, je volba snadná. Pokud dělá obojí — což je čím dál běžnější — je otázkou, u kterého scheduleru jste ochotni zaplatit provozní daň.

SLURM — výchozí volba z HPC, která u čistého tréninku pořád vítězí

Na SLURMu běží víc než 65 % superpočítačů z TOP500 a většina publikovaných frontier tréninků. Pro workloady typu „pošli trénovací úlohu, počkej na výsledky, vezmi si checkpoint“ je správnou odpovědí už dvacet let.

Model uvažování je jednoduchý: partition je pojmenovaný pool uzlů (gpu-5090, cpu-only, bigmem); job je shell skript s direktivami #SBATCH, odesílaný příkazem sbatch; GRES (Generic RESources) eviduje GPU — --gres=gpu:rtxpro6000:2 si řekne o dvě konkrétní karty; gang scheduling je vestavěný.

Minimální slurm.conf pro čtyřuzlový cluster s 8× RTX Pro 6000 Blackwell na uzel:

ClusterName=kentino-lab
SlurmctldHost=head01

SchedulerType=sched/backfill
SelectType=select/cons_tres
SelectTypeParameters=CR_Core_Memory
GresTypes=gpu

# GPU accounting — without these two lines, fair-share runs on CPU-seconds and is meaningless
AccountingStorageType=accounting_storage/slurmdbd
AccountingStorageTRES=gres/gpu
PriorityType=priority/multifactor
PriorityDecayHalfLife=7-0
PriorityWeightFairshare=10000
PriorityWeightAge=1000

# cgroups isolate the GPUs a job is allowed to see
ProctrackType=proctrack/cgroup

NodeName=node[01-04] CPUs=128 RealMemory=1024000 Sockets=2 \
    CoresPerSocket=64 ThreadsPerCore=1 Gres=gpu:rtxpro6000:8 State=UNKNOWN

PartitionName=train Nodes=node[01-03] Default=YES MaxTime=48:00:00 State=UP
PartitionName=interactive Nodes=node04 MaxTime=04:00:00 \
    PriorityTier=10 State=UP

Odpovídající gres.conf na každém uzlu:

AutoDetect=nvml
NodeName=node[01-04] Name=gpu Type=rtxpro6000 File=/dev/nvidia[0-7]

AutoDetect=nvml se dotazuje přímo NVIDIA Management Library, sám zachytí MIG řezy a ušetří Vám ruční psaní cest k zařízením.

Uživatel odešle:

#!/bin/bash
#SBATCH --job-name=qwen-finetune
#SBATCH --partition=train
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=8
#SBATCH --gres=gpu:rtxpro6000:8
#SBATCH --time=12:00:00
#SBATCH --output=logs/%j.out

srun python -m torch.distributed.run \
    --nnodes=2 --nproc-per-node=8 \
    --rdzv-backend=c10d \
    --rdzv-endpoint=$(scontrol show hostnames | head -1):29500 \
    train.py --config configs/qwen72b.yaml

PyTorch Elastic a SLURM do sebe zapadají čistě: SLURM vlastní alokaci, srun spustí jeden proces na úlohu, torch.distributed.run spolu s rendezvous backendem řeší přidělení ranků. Při výpadku uzlu --max-restarts u torchrun spolu s --requeue u #SBATCH obnoví běh z posledního checkpointu. Takhle to dělá každý.

Co dostanete zadarmo: gang scheduling, slábnoucí fair-share, backfill, účtování (každá GPU-sekunda zalogovaná do sacct) a jednoduchou sémantiku — žádné CRD, žádný controller, žádný graf YAML objektů. Co nedostanete: dlouho běžící služby s automatickým restartem, HTTP ingress, rolling updaty, sidecar kontejnery, deklarativní stav. SLURM je dávkový scheduler. Zacházet s ním jako s Kubernetes bolí.

SLURM je správná volba, když: provozujete trénink, dávkovou inferenci nebo simulace; uživatelé píšou shell skripty; a ustojí to jeden SRE na částečný úvazek.

Kde SLURM naráží na strop

Na třech místech. Služby webového typu — nezná pojem „běž navždy, po pádu se restartuj, vystav port 8000“. vLLM se do dlouho běžící SLURM úlohy nacpat dá, ale health-checky, rolling updaty a load balancing už jsou Váš problém. Heterogenní workloady — SLURM předpokládá jeden pool zdrojů; cluster, na kterém běží trénink + inference + Jupyter + monitoring + příprava dat, chce jemnější ovládání. Přísná multi-tenantní izolace — cgroups izolují CPU a paměť; izolace GPU stojí na CUDA_VISIBLE_DEVICES a na tom, že ji kód uživatele respektuje. Žádné namespacy, žádná síťová politika na úrovni úlohy, žádná tenance kontejnerové třídy. Pro laboratoř v pořádku; pro hostovanou službu pro více zákazníků ne.

Jakmile na něco z toho narazíte, správným krokem bývá přidat druhou vrstvu — Kubernetes pro služby — místo toho, abyste mučili SLURM. SUNK od CoreWeave a managed nabídky z roku 2026 provozují SLURM na Kubernetes, takže tentýž cluster zvládá obojí. V měřítku Kentino bývají dva oddělené malé clustery jednodušší.

Kubernetes pro AI: cloud-native cesta

Kubernetes vzniklo proto, aby udrželo v chodu bezstavové webové služby. Pro AI clustery se „všechno ostatní“ přišroubovává zvenčí. Stack roku 2026: NVIDIA GPU Operator (ovladače, CUDA, NCCL, DCGM, device plugin, konfigurace MIG), Kueue (fronta, kvóty, admission), Volcano (scheduler s podporou dávek), Kubeflow Trainer (CRD PyTorchJob, TFJob, MPIJob), KubeRay (Ray na K8s) a Karpenter nebo Cluster Autoscaler pro provisioning uzlů.

Proč je naivní Kubernetes pro AI špatně: výchozí kube-scheduler je FIFO bez gang sémantiky. Klidně spustí 7 z 8 podů distribuovaného tréninku a osmý nechá v Pending, zatímco běžících sedm drží GPU naprázdno. Není to teorie — je to vůbec nejčastější chyba týmů, které se pokusí spustit trénink na clusteru postaveném pro inferenci. Řešením jsou Kueue (admission na úrovni úlohy) a Volcano (gang umístění na úrovni podů). Aktuální best practice je obojí: Kueue nahoře, Volcano pod ním.

Volcano

Volcano je dávkový scheduler z CNCF, který se instaluje vedle kube-scheduleru nebo místo něj. Přidává skutečný gang scheduling se sémantikou minAvailable (pustí nula, nebo N, nikdy ne část), priority front a preempci, strategie fair-share / binpack / topology-aware a prvotřídní podporu pro PyTorchJob, TFJob, MPIJob, RayJob a SparkApplication.

Minimální fronta a k ní gang-schedulovaná trénovací úloha v PyTorchi:

apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
  name: training
spec:
  weight: 4
  capability:
    nvidia.com/gpu: 32
---
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: qwen-finetune
spec:
  schedulerName: volcano
  minAvailable: 16          # gang: all 16 ranks or zero
  queue: training
  policies:
    - event: PodEvicted
      action: RestartJob
  tasks:
    - replicas: 16
      name: worker
      template:
        spec:
          containers:
            - name: pytorch
              image: kentino/pytorch:2.5-cuda13
              resources:
                limits:
                  nvidia.com/gpu: 1
              command: ["torchrun", "--nnodes=16", "--nproc-per-node=1", "train.py"]

Kdy Volcano nepotřebujete: čistě inferenční cluster s nezávislými vLLM Deploymenty. Každý pod vlastní svoje GPU, žádná koordinace napříč pody, výchozí kube-scheduler stačí. Volcano se vyplatí ve chvíli, kdy do clusteru přimícháte distribuovaný trénink.

Kueue a půjčování kvót

Kueue řeší vrstvu, kterou Volcano neřeší: kdo smí spotřebovat kolik clusteru a co se stane, když jeden tým zahálí.

apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
  name: rtxpro6000
spec:
  nodeLabels:
    nvidia.com/gpu.product: "RTX-PRO-6000-Blackwell"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
  name: team-research
spec:
  cohort: "shared-gpu"
  resourceGroups:
    - coveredResources: ["nvidia.com/gpu"]
      flavors:
        - name: rtxpro6000
          resources:
            - name: "nvidia.com/gpu"
              nominalQuota: 16
              borrowingLimit: 8

Oba týmy v kohortě mají garantovaných 16 GPU a mohou si půjčit až 8 z nevyužitého poolu toho druhého. Vysokoprioritní práce půjčenou kapacitu preemptuje. Roadmapa Kueue pro rok 2026 cílí na MultiKueue (dispatch napříč clustery) a kooperativní preempci — úloze, která umí checkpointovat, lze říct „ulož stav a uvolni místo do 60 sekund“ místo toho, aby byla rovnou zabita.

MIG a sdílení GPU

NVIDIA device plugin ve výchozím stavu alokuje celé GPU. Pro trénink a velkou inferenci je to správně; pro malou inferenci, notebooky nebo vývoj je to plýtvání. Tři režimy sdílení: MIG (hardwarová izolace paměti i chyb, produkční multi-tenantní inference), MPS (kooperativní, bez izolace), time-slicing (bez izolace, jen pro vývoj).

MIG existuje na H100/H200, A100 a B200 — na žádném GPU z nabídky Kentino ne. RTX 5090, RTX 4090, RTX Pro 6000 Blackwell, L40 ani L4 MIG nepodporují. Pokud Váš návrh vyžaduje hardwarově izolované oddíly GPU, omezuje Vás to na SXM/datacentrové díly, které Kentino nestaví. Time-slicing inzeruje N virtuálních GPU na jedno fyzické a scheduler vůbec netuší, že jsou přetížená — používejte jej jen pro vývoj.

V čem je Kubernetes dobré: dlouho běžící inferenční služby (vLLM Deploymenty škálované přes HPA podle hloubky fronty, rolling updaty, health checky — SLURM nemá nic srovnatelného), heterogenní workloady na jednom clusteru, ekosystém (Prometheus, Grafana, Argo). Co za to zaplatíte: funkční stack K8s + GPU Operator + Kueue + Volcano + Kubeflow má minimálně 20 komponent. Realistický odhad: Kubernetes znamená 5–10× vyšší provozní zátěž než SLURM u čistě dávkového tréninku.

Kubernetes je správná volba, když: na clusteru běží inferenční služby vedle tréninku, máte platformový tým, záleží Vám na tom, aby bylo všechno deklarativní, nebo potřebujete přenositelnost mezi clustery.

Ray a KubeRay — distribuované výpočty nativně v Pythonu

Ray je jiné zvíře. Ve smyslu SLURMu nebo K8s to vlastně ani není clusterový scheduler — je to distribuovaný Pythonový runtime, který s sebou nese scheduler, object store a autoscaler. Píšete Python s dekorátory @ray.remote a Ray si sám domyslí, kde kterou úlohu spustit.

Kam se Ray hodí: ladění hyperparametrů (Ray Tune — stovky běhů paralelně, špatné se ořežou brzy; případ užití, pro který Ray vznikl a ve kterém je dodnes nejlepší), zpětnovazební učení (RLlib — prostředí a učící se agenti jako aktoři, což na Ray sedne čistě a na dávkové úlohy SLURMu mizerně), distribuovaný trénink (Ray Train, obaluje PyTorch DDP / FSDP / DeepSpeed), serving modelů (Ray Serve, nativně v Pythonu, vlastní multi-model pipeline) a předzpracování dat (Ray Data). Co Ray není: multi-tenantní dávkový scheduler pro sdílený cluster. Ray předpokládá, že cluster vlastní jedna aplikace.

KubeRay je operátor, který Ray provozuje na Kubernetes. Tři CRD: RayCluster (dlouho žijící), RayJob (jednorázový), RayService (Ray Serve, rolling updaty). Minimální RayCluster:

apiVersion: ray.io/v1
kind: RayCluster
metadata:
  name: rl-cluster
spec:
  rayVersion: '2.55.0'
  headGroupSpec:
    rayStartParams: { dashboard-host: '0.0.0.0' }
    template:
      spec:
        containers:
          - name: ray-head
            image: rayproject/ray:2.55.0-py311-cu125
            resources:
              limits: { cpu: 8, memory: 32Gi }
  workerGroupSpecs:
    - groupName: gpu-workers
      replicas: 4
      minReplicas: 0
      maxReplicas: 8
      rayStartParams: {}
      template:
        spec:
          containers:
            - name: ray-worker
              image: rayproject/ray:2.55.0-py311-cu125
              resources:
                limits:
                  cpu: 16
                  memory: 128Gi
                  nvidia.com/gpu: 4

KubeRay škáluje skupinu workerů mezi minReplicas a maxReplicas podle toho, jak Ray vidí čekající úlohy. V kombinaci s Kueue (RayJob + gang scheduling přes Kueue je zdokumentovaný a funguje) dostanete multi-tenantní Ray na multi-tenantním K8s clusteru — produkční nasazení, které většina „Ray shopů“ skutečně provozuje.

Kdy dává smysl samostatný Ray (bez K8s): malá výzkumná laboratoř, kde cluster vlastní jeden člověk, dynamika je důležitější než multi-tenance a workload je těžký na RL nebo hledání hyperparametrů. Hybrid, ke kterému většina týmů dojde: SLURM nebo K8s jako základní vrstva, která vlastní uzly a multi-tenanci; Ray spouštěný uvnitř SLURM úlohy nebo K8s namespace po dobu workloadu jednoho uživatele. Neinstalujte Ray jako svůj nejvyšší scheduler.

Run:ai a Determined — komerční patro

Dvě placená řešení se objevují dost často na to, aby stálo za to je zmínit. Obě míří na stejnou bolest: K8s + Volcano + Kueue + GPU Operator je spousta YAMLu a některé organizace raději koupí, než aby stavěly.

NVIDIA Run:ai (akvizice 2024, přejmenováno 2025) je GPU scheduler nativní pro K8s. Dělení GPU na zlomky rozděluje jedno GPU mezi workloady na úrovni paměti — požadavky typu 0.5 GPU, dynamické zvětšování a bin-packing. Run:ai se vyplatí v podnicích s 10+ ML týmy, které soupeří o sdílená GPU. Pod touto hranicí pokryje Kueue + GPU Operator většinu téhož zdarma.

Determined.AI (HPE, 2021) je spravovaná trénovací platforma — sledování experimentů, hledání hyperparametrů, správa checkpointů a distribuovaný trénink v jednom produktu. Nejlépe sedne výzkumným týmům, které chtějí vyladěný dashboard, aniž by samy integrovaly pět nástrojů.

Problém interaktivních notebooků

Vzorec, který dostihne skoro každý sdílený GPU cluster: výzkumníci chtějí kvůli vývoji přístup k GPU přes JupyterHub a to musí koexistovat s dlouho běžícími trénovacími úlohami, které drží celé uzly. Naivní odpověď — jedno vyhrazené GPU na notebook — zahodí 80 % clusteru. Striktní odpověď — nutit výzkumníky všechno posílat přes sbatch — je vyžene na laptopy s hračkovými modely.

Tři funkční vzorce: SLURM salloc + Jupyter na alokaci (salloc --gres=gpu:1 --time=4:00:00, na alokovaném uzlu spustíte Jupyter server a tunelujete se dovnitř; tvrdý časový limit, GPU řádně zaúčtované — nejčistší odpověď pro SLURM cluster), Kubernetes + JupyterHub + Kueue (pody s notebooky přes nízkoprioritní frontu, trénovací úlohy preemptují nečinné notebooky), nebo Run:ai s dělením GPU na zlomky (každý notebook dostane 0.25 / 0.5 GPU). Ať zvolíte cokoli, nastavte interaktivním sezením časový limit — notebook bez timeoutu je GPU natrvalo vyřazené z clusteru.

Upřímná realita malého týmu

Většina obsahu o schedulerech na internetu předpokládá cluster o 256 GPU a platformový tým. Realistický zákazník Kentina je blíž 1–4 uzlům, 4–32 GPU celkem a 2–6 uživatelům, kteří se navzájem znají a domluví se na Slacku. Pro takové nasazení scheduler nepotřebujete.

# user 1
ssh node01
tmux new -s my-training
CUDA_VISIBLE_DEVICES=0,1,2,3 python train.py
# Ctrl-B D to detach

# user 2 — coordinates on Slack first
ssh node01
nvidia-smi                              # which GPUs are free?
tmux new -s other-training
CUDA_VISIBLE_DEVICES=4,5,6,7 python train.py

A to je celý systém plánování úloh. SLURM se začne vyplácet zhruba od 16 GPU nebo 8 uživatelů, podle toho, co nastane dřív. Pod touto hranicí provozní režie převáží přínos. Scheduler instalujte, až když selhává lidská koordinace, ne dřív.

Kdy se který nástroj hodí — shrnutí

Scénář Doporučení
1–2 uzly, 4–16 GPU, 2–6 uživatelů, kteří spolu mluví SSH + tmux + nvidia-smi. Žádný scheduler.
Výzkumná laboratoř, 4–32 uzlů, dávkové trénovací úlohy SLURM. Nudný, prověřený, sedne.
Inferenční platforma obsluhující zákaznický provoz Kubernetes + GPU Operator. Žádný dávkový scheduler.
Smíšený cluster: trénink + inference + nástroje Kubernetes + Kueue + Volcano + Kubeflow.
Hodně distribuovaného Pythonu: RL, hledání hyperparametrů Ray (nebo KubeRay) nad SLURMem nebo K8s.
10+ ML týmů soupeří o GPU, rozpočet na nástroje Run:ai na Kubernetes.
Spravované trénovací experimenty + sledování Determined.AI.
200+ GPU, více týmů, více workloadů Federovaně: SLURM na dávky, K8s na služby.

Co dělat dál — rozhodovací strom

Projděte to po pořádku. První „ano“ debatu ukončuje.

  1. Méně než 16 GPU a méně než 8 uživatelů, kteří spolu mluví? Ano → žádný scheduler. Sepište konvence do markdown souboru. Vraťte se k tomu, až koordinace přestane fungovat.
  2. Běží na clusteru kromě tréninku i dlouho běžící inferenční služby? Ano → základem je Kubernetes. Přidejte GPU Operator, pak Kueue a pak Volcano, pokud je ve hře distribuovaný trénink. Ne → základem je SLURM.
  3. Máte platformový tým nebo rozpočet na něj (0.5–1.0 FTE po dobu šesti měsíců, 0.25 FTE v ustáleném stavu)? Ne → zůstaňte u SLURMu bez ohledu na mix workloadů. Daň za K8s je reálná.
  4. >10 týmů soupeří o čas na GPU s přísnými nároky na kvóty? Ano → zvažte Run:ai. Ne → Kueue a kohorty Vás dostanou z 80 % tam, kam potřebujete.
  5. Workload těžký na RL, hledání hyperparametrů nebo distribuovaný Python? Ano → Ray (KubeRay na K8s, nebo salloc + Ray na SLURMu). Ne → Ray vynechte.
  6. Hardware s podporou MIG (datacentrové karty)? V nabídce Kentino ne → počítejte s alokací celých GPU nebo s time-slicingem jen pro vývoj. Nestavte návrh na MIG.

Většina konverzací v Kentinu končí u kroku 1, 2 nebo 3. Zbytek je dekorace.

Související články: distribuovaný trénink v K02, inferenční clustery v K03, úložiště clusteru v K04, řešení výpadků v K06, strop propustnosti PCIe v K07.


Tohle je součást Kentino Wiki, referenční série o AI výpočtech, robotice a systémech, které je spojují. Komentáře a opravy uvítáme na info@kentino.com.