SFLOWWhy sflow

Write the workload once.
Run it anywhere.

1
workload.yaml

Unchanged. Tasks, GPUs, health checks.

docker.yamlslurm.yamlk8s.yaml

Workstation, Slurm or Kubernetes: swap one file.

SFLOW02The cost of a rewrite

Porting one job means
rewriting all of this.

Every launch script has to handle
Workstation
Slurm
Kubernetes
Launch command, container flags
rewrite
rewrite
rewrite
Which GPUs each task gets
rewrite
rewrite
rewrite
Start order, wait until ready
rewrite
rewrite
rewrite
Spot a crashed task
rewrite
rewrite
rewrite
Clean up on success, failure, Ctrl-C
rewrite
rewrite
rewrite
Collect logs and results
rewrite
rewrite
rewrite

Every fix, three times

A timeout bumped on Slurm stays wrong on Kubernetes until someone remembers.

Copies drift apart

Three scripts evolve separately; the "same" job quietly stops being the same.

Numbers stop comparing

Different launch glue on each platform: benchmark results are no longer like for like.

6 concerns × 3 platforms = 18 pieces of glue to write, debug and keep in sync.

SFLOW03The idea

Two files. Only one of them changes.

Those six concerns are written once. Only how to launch changes per platform.

The workload
workload.yaml
  • commands and start order
  • GPUs per task
  • readiness and failure checks
  • cleanup, logs, results: sflow does these
Written once
The backend
docker.yamlslurm.yamlk8s.yaml

How this platform launches it.

One per platform, shared
SFLOW04Real file, unchanged

The workload names roles,
never platforms.

workloads/vllm_serve.yaml
- name: server
  operator: server
  script:
    - set -x
    - >
      vllm serve ${{ artifacts.LOCAL_MODEL_PATH.path }}
      --served-model-name ${{ variables.SERVED_MODEL_NAME }}
      --host 0.0.0.0 --port 8000
      --tensor-parallel-size ${{ variables.SERVER_GPUS }}
      --trust-remote-code
  resources:
    gpus:
      count: ${{ variables.SERVER_GPUS }}
operator: server

A role. The backend decides what launches it.

gpus: count

How many GPUs, never which node or device.

no srun · no docker · no pod

Nothing in this file ties it to a platform.

SFLOW05Real files, one per platform

You write the role.
sflow writes the launch.

The workload asks foroperator: serverand from each backend file sflow generates the native launch command:

Workstation

You write · backends/docker.yaml
- name: server
  type: docker_run
  image: ${{ variables.SERVER_IMAGE }}
sflow generates thisdocker run --rm \ --gpus "device=0,1,2,3" -v … \ nvcr.io/…/vllm-runtime:1.0.0 …

Slurm

You write · backends/slurm.yaml
- name: server
  type: srun
  container_image: ${{ variables.SERVER_IMAGE }}
  container_writable: true
  mpi: pmix
  ntasks_per_node: 1
sflow generates thissrun --nodes 1 --nodelist cluster-node0 \ --ntasks-per-node 1 --mpi pmix \ --container-image nvcr.io/…/vllm-runtime:1.0.0 …

Kubernetes

You write · backends/k8s.yaml
- name: server
  type: k8s
  image: ${{ variables.SERVER_IMAGE }}
sflow generates thiskubectl apply -f server.k8s.yaml # Pod · nvidia.com/gpu: 4 # pinned to the reserved node
SFLOW06Proof, from the repo

The same file. Three platforms.

54lines of workload,
never edited
3platforms it
runs on
1flag that
changes
Workstation
sflow run -f backends/docker.yaml -f workloads/vllm_serve.yaml -f benchmark.yaml
Slurm
sflow run -f backends/slurm.yaml  -f workloads/vllm_serve.yaml -f benchmark.yaml
Kubernetes
sflow run -f backends/k8s.yaml    -f workloads/vllm_serve.yaml -f benchmark.yaml

Add --dry-run to any of them: the whole plan, without touching a cluster.

SFLOW07What you gain

What you gain.

1

Debug small, submit big

Prove it on a workstation with Docker, then submit the identical workload to the cluster.

2

Platform glue, written once

One person writes the Slurm or Kubernetes backend file. Everyone else reuses it.

3

Fair platform comparisons

Same workload, same benchmark, different backend: the comparison is like for like.

4

Scale by numbers, not rewrites

More nodes, GPUs or replicas is a value change. Multi-node disaggregated LLM serving ships as ordinary recipes.

SFLOW08Get started

Try it in a minute.

In your terminal
$ uv tool install nv-sflow
$ sflow sample self_contained/local/hello_world \
    -o hello.yaml
$ sflow run -f hello.yaml
Or ask your AI agent

“Set up sflow for me by followinghttps://raw.githubusercontent.com/NVIDIA/nv-sflow/main/docs-site/agents-src/setup.mdstep by step, then tell me what you installed and where.”