Skip to main content
The recommended production shape: one ephemeral RayCluster (RayJob) per training job, destroyed on reaching a terminal state, with resource reclamation guaranteed by K8s.

Prerequisites

  1. A Kubernetes cluster (GPU nodes with the device plugin installed);
  2. KubeRay operator (installed via helm, v1.4+);
  3. Object storage (required: job packages are distributed into containers via presigned URLs);
  4. GPU nodes labeled by series: kubectl label node <n> starforge/gpu-series=h200.

Configuration

Key semantics

The console assembles user code, the authoritative JobSpec, manifest, and runner.pex into a content-addressed Capsule and uploads it to object storage. HTTPS archives use Ray’s runtimeEnvYAML.working_dir; for HTTP-only storage, an init container in every Ray Pod verifies the transport SHA-256 and exposes the same file:// path to the runtime-env agent. Training images need no platform bootstrap package.
head = machine zero of the primary pool; multi-pool jobs get one worker group per pool (nodeSelector by series, pinned via Ray custom resources). shutdownAfterJobFinishes=true + backoffLimit=0: training never retries blindly. The platform deletes the RayJob immediately after archiving terminal logs; TTL is only a failure fallback.
Cluster capacity is computed live from node nvidia.com/gpu capacity plus series labels; unschedulable nodes count as blocked. The per-series capacity shown in the UI and the nodes the scheduler can actually land on come from the same source.
The real cause only lives in K8s Events (image pull failure / no node satisfying the nodeSelector / not enough GPUs) — the job detail’s event view surfaces them directly. Jobs exceeding the preRunning deadline are failed automatically, so they never occupy the queue indefinitely.
FORGE_K8S_GPU_PASSTHROUGH=0: Pods don’t request nvidia.com/gpu, while Ray logical resources work as usual. For running the closed loop on kind/CI; production keeps the default.

Playground

Supported: standalone vLLM Pods (not RayJobs), accessed via the K8s API proxy, reclaimed on TTL expiry.

Quick verification