Running on Slurm#
On Slurm, a swarm is a job array of vLLM replicas fronted by an Nginx load
balancer, with roles assigned by SLURM_NODEID.
What up submits#
domyn-swarm up -c config.yaml --replicas 3
-c/--config: Path to the YAML configuration-r/--replicas: Replica count override
Three things happen:
An array job starts one vLLM server per replica.
A load-balancer job starts Nginx. Nginx waits for every replica before it exposes one endpoint.
A SQLite state record lets later commands address the swarm by name.
Building the Singularity images#
domyn-swarm uses Singularity as its container engine on Slurm. Build the two
required images from the definition files in
examples/singularity_images/,
on a machine with sudo, or with --fakeroot if your site enables it:
# NGINX load balancer image
sudo singularity build nginx.sif examples/singularity_images/nginx.def
# vLLM runtime image
sudo singularity build vllm.sif examples/singularity_images/vllm.def
Then add the image paths to the configuration:
model: "deepseek-ai/DeepSeek-R1-0528" # whatever model you want to deploy
image: /shared/images/vllm.sif # vLLM container; optional if you run from a venv
backend:
type: slurm
endpoint:
nginx_image: /shared/images/nginx.sif # required for the load balancer
Practical notes:
Put the
.siffiles on a shared path readable by every compute node.Singularity must be available on the execution nodes.
If your site disables
--fakeroot, build with admin privileges elsewhere and copy the.sifonto the shared filesystem.imageis optional if you run vLLM from a virtual environment instead of a container.endpoint.nginx_imageis always required.
Path validation before submission#
up examines configuration paths on the submit host before submission. If a path
cannot be used, the command does not submit the swarm:
Config check failed: 1 path in swarm.yaml cannot be used
image
/shared/images/vllm.sif
-> does not exist (deepest existing parent: /shared)
Nothing was submitted. Fix the paths above, or pass --skip-preflight to launch anyway.
The hint names the deepest path segment that exists. In this example, images
is missing. The command lists every invalid path and exits with status 2.
Checked: image, model, endpoint.nginx_image, the monitoring sidecar
images (container mode only), mounts sources and venv_path. Images can be a
.sif or a Singularity sandbox directory.
The preflight validation skips values that the submit host cannot resolve. These
values include registry references, Hugging Face repository IDs, bare names,
relative paths, unset variables, and paths under unreadable directories.
system_mounts uses per-node validation. See Site mounts. The validation
does not apply to Lepton.
Note
A venv_path that does not exist is now an error. Earlier versions ignored it
and used the ambient Python.
Use --skip-preflight when paths are visible only from compute nodes.
job submit and job submit-script also accept this flag. The Python API raises
domyn_swarm.exceptions.SwarmConfigPathError, and DomynLLMSwarm takes
preflight=False.
Bind mounts#
backend.mounts adds bind mounts to the vLLM containers:
backend:
type: slurm
mounts:
- /scratch/datasets # bound at the same path inside the container
- /host/config:/etc/app/config:ro # host:container, with an option
Each entry is either /path, bound at the same path inside the container, or
/host/path:/container/path with an optional :ro or :rw suffix.
Entries pass unchanged to Singularity’s --bind. domyn-swarm requires an
absolute source path and permits at most a source:dest:opts triple. The
container runtime reports errors such as a missing path or invalid option. For
the full bind syntax, see
Apptainer or
SingularityCE.
Site mounts#
Some clusters require host paths in every container for software loaded by
modules. For example, CINECA Leonardo uses /leonardo/prod/opt. Put site paths
in backend.system_mounts. Prefer the site
defaults file over each swarm configuration:
# defaults.yaml
slurm:
system_mounts:
- /leonardo/prod/opt
# or per deployment
backend:
type: slurm
system_mounts:
- /leonardo/prod/opt
The syntax matches backend.mounts. A node binds an entry only when the host
path exists. Otherwise, the job log contains a warning. This behavior permits a
configuration to move between clusters. /dev/infiniband uses the same rule
without explicit configuration.
Modules and sbatch preamble#
Two fields inject site-specific setup into the generated cluster script:
backend:
type: slurm
modules:
- cuda/12.1
- singularity
preamble:
- "#SBATCH --exclusive"
- "export NCCL_DEBUG=WARN"
modules become module load lines. preamble lines appear before the module
loads. Use the preamble for extra sbatch directives or shell setup.
Replicas larger than one node#
A replica that needs more GPUs than one node becomes a Ray cluster. The cluster
has one head and enough workers to reach gpus_per_replica. vLLM tensor
parallelism spans these nodes.
This behavior follows from the arithmetic:
model: "deepseek-ai/DeepSeek-R1-0528"
gpus_per_replica: 16 # more than one node holds
gpus_per_node: 4 # so each replica spans four nodes
replicas: 2
gpus_per_replica > gpus_per_node sets requires_ray. This value:
Selects
llm_swarm_ray.sh.j2instead ofllm_swarm.sh.j2. Both templates use_swarm_common.sh.j2for shared behavior.Enables
watchdog.rayto probe cluster liveness with the HTTP probe.Enables
monitoring.ray_metricswhen monitoring is on. The dashboard then includes Ray metrics and panels.
gpus_per_replica must be a multiple of gpus_per_node in this case.
Any other value leaves a partly used node in the replica and is rejected
with When gpus_per_replica > gpus_per_node, gpus_per_replica must be a multiple
of gpus_per_node.
backend.template_path selects a custom template and disables automatic
selection. A custom template must support Ray when the deployment requires it.
Node selection and limits#
backend.partition, account and qos are required. Beyond those,
exclude_nodes and node_list accept Slurm’s own syntax
(node[001-004]), time_limit caps the allocation, and mail_user enables
END and FAIL notifications. The load-balancer job is configured separately under
backend.endpoint, including its own optional qos override.
backend.requeue defaults to true and emits #SBATCH --requeue. Replica jobs
then return after a node failure or preemption. The Ray head can also request a
requeue after a cluster failure. Set it to false on sites that forbid requeue:
backend:
type: slurm
requeue: false
The directive is then omitted. A Ray head that loses its cluster exits non-zero
instead of calling scontrol requeue. The replica stays down instead of
restarting. This site property also belongs in defaults.yaml as
slurm.requeue.
Full field list: Configuration.
Shutting down#
domyn-swarm down my-swarm-name
The command takes a swarm name. It uses scancel to stop the load balancer and
every replica job.
Metrics#
The load balancer can run Prometheus and a GPU exporter as sidecars. This Slurm-only feature is off by default. See Metrics and dashboards.