- Preserve existing CI and add configurable GPU backend routing - Limit execution to 2 active PRs, 4 GPUs per PR, and 8 GPUs total - Add persistent admission, cancellation recovery, and backend statuses - Document deployment and add infrastructure regression tests
253 lines
13 KiB
Markdown
253 lines
13 KiB
Markdown
# Selectable GPU CI Backends
|
|
|
|
GPU CI can use the existing Slurm dispatcher, Modal, or GB200 Kubernetes Jobs
|
|
in the `vllm` namespace. GitHub and Buildkite remain the trigger and reporting
|
|
systems. `vllm` names the cluster namespace here; tests run FastVideo's existing
|
|
lane scripts rather than a vLLM inference server.
|
|
|
|
The default remains Slurm. The existing `.buildkite/pipeline.yml`, private
|
|
Slurm uploader, and dormant Modal launchers are preserved. Deploying the new
|
|
trusted uploader is an operator step; merging these files does not change the
|
|
live Buildkite pipelines or create cluster resources. See
|
|
[CI/CD Architecture](ci_architecture.md) for the existing installation.
|
|
|
|
## Execution and Limits
|
|
|
|
```text
|
|
GitHub PR / slash command / schedule
|
|
-> trusted Buildkite bootstrap
|
|
-> slurm: existing validated graph and private dispatcher
|
|
-> modal or vllm: one trusted suite coordinator
|
|
-> shared PR admission and GPU reservations
|
|
-> isolated GPU worker per existing lane
|
|
-> lane results, logs, and backend-specific suite status
|
|
```
|
|
|
|
All new Modal and `vllm` coordinators share one admission database. It enforces:
|
|
|
|
- At most two distinct PRs with admitted GPU work.
|
|
- At most four reserved GPUs per PR across its concurrent builds and lanes.
|
|
- At most eight reserved GPUs across both backends combined.
|
|
- Additional PRs wait without creating GPU workers.
|
|
|
|
A PR is identified by repository and PR number, so Fastcheck, merge builds,
|
|
manual reruns, and separate attempts share its allowance. Its slot remains
|
|
occupied between lanes until all admitted builds for that PR finish. A
|
|
non-PR build, including a schedule on `main`, consumes its own slot and the
|
|
same GPU budget. The preserved Slurm dispatcher has its existing independent
|
|
limits; this new admission database does not control legacy Slurm jobs.
|
|
|
|
Lanes retain their existing one-, two-, or four-GPU requirements. Four-GPU
|
|
SSIM and training lanes wait for that PR's other lanes to release capacity.
|
|
Selected integration lanes wait for the golden gate and are skipped if it
|
|
fails. CPU-only GitHub checks are unaffected. Pending admission is bounded by
|
|
`queue_timeout_seconds`, initially six hours. The coordinator's Buildkite
|
|
command timeout is eight hours, including admission and lane waits after the
|
|
command starts; time waiting for a Buildkite agent is outside that timeout.
|
|
|
|
Reservations persist before a worker is created. Cancellation releases them
|
|
only after worker termination is confirmed. A lost coordinator, uncertain
|
|
create response, or unavailable backend retains its reservations until
|
|
recovery confirms cleanup. There is no heartbeat expiry that silently frees
|
|
GPUs while an old worker could still be running.
|
|
|
|
## Operator Installation
|
|
|
|
Use an operator-reviewed immutable checkout under
|
|
`/opt/fastvideo-gpu-ci/source`. Install the supplied `scripts/gpu_ci/run` and
|
|
`scripts/gpu_ci/upload` wrappers as `/opt/fastvideo-gpu-ci/run` and
|
|
`/opt/fastvideo-gpu-ci/upload`. They invoke the reviewed Python entrypoint
|
|
with isolated import mode. Install the supplied files instead of generating
|
|
shell wrappers from build metadata:
|
|
|
|
```bash
|
|
install -m 755 /opt/fastvideo-gpu-ci/source/scripts/gpu_ci/run /opt/fastvideo-gpu-ci/run
|
|
install -m 755 /opt/fastvideo-gpu-ci/source/scripts/gpu_ci/upload /opt/fastvideo-gpu-ci/upload
|
|
```
|
|
|
|
The controller needs Python 3.10 or newer, PyYAML,
|
|
the Buildkite agent, and `kubectl`; Modal additionally needs the reviewed
|
|
Modal SDK and a controller-side Modal credential.
|
|
|
|
Copy [the configuration example](../../scripts/gpu_ci/config.example.json)
|
|
to `/etc/fastvideo-gpu-ci.json`. Keep the installation and configuration
|
|
operator-owned and unwritable by workers. Configure the actual legacy
|
|
`slurm_uploader` command, replace each enabled backend's image placeholder
|
|
with a reviewed registry digest, and leave `default_backend` as `slurm`
|
|
during canaries. The checked-in placeholders deliberately cannot start jobs.
|
|
|
|
The permanent dispatcher must reach the Kubernetes API independently of a
|
|
developer laptop, SSH tunnel, or Tailscale session. The existing CPU development
|
|
pod is useful for investigating access, but is not a production CI service.
|
|
Use a dedicated controller identity and a separate `gpu-ci-dispatch` Buildkite
|
|
queue. The trusted bootstrap also needs access to the existing Slurm uploader
|
|
while that backend remains enabled.
|
|
|
|
Run all coordinators on **one host**, with `state_path` and `artifacts_dir` on
|
|
its persistent local disk. The implementation uses SQLite transactions and
|
|
local file locks. Do not place the database or locks on Lustre/NFS, run
|
|
independent database copies, or scale controller replicas across nodes. Those
|
|
configurations would invalidate the global limits. Multiple Buildkite agent
|
|
processes on the same host can share the installation and ledger; enough
|
|
agents are needed for concurrent suite coordinators and queued work.
|
|
|
|
Configure agent-owned hooks to skip repository checkout and reject commands
|
|
other than the trusted uploader and coordinator. Disable repository hooks
|
|
and plugins on this queue. Do not use a PR checkout to load `scripts/gpu_ci`,
|
|
its configuration, or its worker entrypoint. Build metadata is validated by
|
|
the dispatcher; arbitrary environment variables are not forwarded into GPU
|
|
workers. Buildkite, Kubernetes, and Modal control-plane credentials stay on
|
|
the dispatcher.
|
|
|
|
For Kubernetes, provision namespace-scoped permissions to create/get/delete
|
|
Jobs and read Pods and their logs. Worker Pods disable service-account token
|
|
mounting and request the exact GPU count on ARM64 GB200 nodes. The image must
|
|
include the expected `/opt/venv` runtime, CUDA/SM100 support, and the reviewed
|
|
FA4 dependencies. Use a separate AMD64 image digest for Modal. The Modal
|
|
profile preserves H100 for encoder, custom-kernel, and VSA lanes, and L40S
|
|
for the remaining lanes. Its reviewed image must support both SM89 and
|
|
SM90a. Attention settings are selected per backend and lane to preserve the
|
|
existing Modal and GB200 FA4 profiles; do not replace them with one global
|
|
attention override. Validate the images against their respective hardware
|
|
before enabling merge gates.
|
|
|
|
Optional Kubernetes configuration includes `context`, `hf_secret`,
|
|
`hf_secret_key`, `cache_pvc`, `cache_subpath`, `artifacts_pvc`, and
|
|
`artifacts_subpath`. Only provide a read-only Hugging Face credential when
|
|
private/gated downloads require it. PR workers are untrusted and can access
|
|
any credential supplied to them, so never provide a reference-publication
|
|
or other write-capable token. Prefer a pre-populated read-only cache.
|
|
|
|
Use dedicated CI PVCs and relative CI subpaths. The personal
|
|
`lustre-pvc-vllm` and `nfs-pvc-vllm` claims are rejected. The cache is mounted
|
|
read-only; mutable references and locks stay inside the worker. The artifact
|
|
init container prepares each Job's dedicated artifact subdirectory before
|
|
the worker mounts it. An
|
|
operator quota or admission policy scoped to CI can provide a second GPU
|
|
ceiling; do not apply an eight-GPU quota to the shared `vllm` namespace if it
|
|
would also cap other users' work.
|
|
|
|
## Wire Every Buildkite Entry Pipeline
|
|
|
|
Set each pipeline's operator-owned bootstrap command to
|
|
`/opt/fastvideo-gpu-ci/upload`. Apply this to all three entry pipelines:
|
|
|
|
| Pipeline | Trigger and scope |
|
|
|---|---|
|
|
| `pr-fastcheck` | Automatic PR webhook; `TEST_SCOPE=fastcheck` or unset. |
|
|
| `ci` | Existing API triggers for Fastcheck, full, merge, direct, and scheduled SSIM. Keep its incoming PR webhook disabled to avoid duplicate builds. |
|
|
| `fastvideo-performance-lane` | Existing schedule; `TEST_SCOPE=direct`, `TEST_TYPE=performance`. |
|
|
|
|
The wrapper resolves `CI_GPU_BACKEND` from the build environment, falling
|
|
back to `default_backend` in the trusted configuration. Allowed values are
|
|
exactly `slurm`, `modal`, and `vllm`; unknown values fail. For Slurm, upload
|
|
delegates to the unchanged private uploader. For Modal or `vllm`, it uploads
|
|
one fixed `/opt/fastvideo-gpu-ci/run` command on the dedicated queue, with
|
|
the selected backend and scope pinned in step environment.
|
|
|
|
Set `CI_GPU_BACKEND=vllm` in the Buildkite build environment for a rack canary,
|
|
or `modal` for a Modal canary. The existing API build payload can carry the
|
|
same string in its `env` object. Automatic PR webhook builds inherit the
|
|
operator's configured default unless pipeline/build configuration explicitly
|
|
overrides it. Do not put backend selection inside a PR-controlled command.
|
|
|
|
Keep the existing exact `BUILDKITE_COMMIT`, repository, PR identity, and
|
|
`TEST_SCOPE` metadata. Direct runs also need an allowlisted `TEST_TYPE`.
|
|
Merge runs need the trusted base-branch planner's `MERGE_TEST_PLAN`,
|
|
`MERGE_GOLDEN_TESTS`, and `MERGE_SSIM_TESTS`. Full/direct/scheduled quality
|
|
runs keep their complete matrices. The worker fetches and verifies the
|
|
immutable commit before installing dependencies or invoking a lane script.
|
|
|
|
The new Modal adapter uses bounded one-to-four-GPU sandboxes and the same
|
|
lane scripts as Kubernetes. It does not reactivate `pr_test.sh` or the old
|
|
Modal SSIM fan-out, which cannot enforce this shared four-GPU-per-PR budget.
|
|
The legacy files remain available for their existing manual workflows.
|
|
|
|
## Statuses and Default-Backend Cutover
|
|
|
|
The selected adapter reports separate suite contexts:
|
|
|
|
| Scope | GitHub context |
|
|
|---|---|
|
|
| Fastcheck | `gpu-ci/<backend>/fastcheck-passed` |
|
|
| Merge or explicit full suite | `gpu-ci/<backend>/full-suite-passed` |
|
|
| Direct lane | `gpu-ci/<backend>/direct-test-completed` |
|
|
| Scheduled SSIM | `gpu-ci/<backend>/scheduled-ssim-passed` |
|
|
|
|
The repository variable `CI_GPU_BACKEND` controls which new backend can
|
|
publish the existing required `fastcheck-passed` and `full-suite-passed`
|
|
contexts. Empty or `slurm` preserves the existing status behavior. `modal`
|
|
or `vllm` enables `ci-gpu-backend-status.yml`, which reads the latest statuses
|
|
for that one backend and mirrors both required contexts. A missing result
|
|
becomes pending; failure and error remain failures. It never combines one
|
|
backend's Fastcheck with another backend's full-suite result. Late status
|
|
events re-read current state instead of replaying stale event payloads.
|
|
|
|
Direct tests are diagnostic and do not promote a whole suite on the new
|
|
backends. Rerun the matching Fastcheck or merge/full suite to clear its gate.
|
|
Per-build tests on the other new backend remain separate diagnostics. The
|
|
legacy direct-test aggregation workflow is disabled while a new backend is
|
|
selected. These workflows retain the existing trust assumption that only
|
|
authorized status-writing integrations can publish CI status contexts.
|
|
|
|
For production cutover, drain existing Slurm builds: its preserved pipeline
|
|
still emits canonical status contexts. The new uploader rejects a Slurm
|
|
override when `default_backend` is `modal` or `vllm`, preventing later legacy
|
|
builds from overwriting the promoted backend's checks. Ensure no old bootstrap
|
|
bypasses the new uploader. Synchronize the operator `default_backend` and
|
|
the GitHub repository variable, then clear or rerun required checks for all
|
|
open PRs. Old green contexts do not become new-backend validation merely
|
|
because a setting changed. Run both Fastcheck and the merge/full suite on
|
|
the promoted backend before allowing merge. Apply the same drain and rerun
|
|
procedure when rolling back to Slurm.
|
|
|
|
## Validation and Recovery
|
|
|
|
Inspect the rendered opt-in pipeline without submitting a build:
|
|
|
|
```bash
|
|
CI_GPU_BACKEND=vllm TEST_SCOPE=fastcheck \
|
|
/opt/fastvideo-gpu-ci/venv/bin/python -I \
|
|
/opt/fastvideo-gpu-ci/source/scripts/gpu_ci/entrypoint.py render \
|
|
--config /etc/fastvideo-gpu-ci.json
|
|
```
|
|
|
|
Validate a one-GPU lane, then a two-/four-GPU lane and the complete Fastcheck
|
|
suite. Exercise two PRs plus a third waiter, concurrent builds of the same
|
|
PR, cancellation, retries, and coordinator restart. Confirm observed GPU
|
|
reservations never exceed two PRs, four per PR, or eight in total. A GPU
|
|
reservation includes a pending worker, so unavailable nodes cannot cause
|
|
the controller to submit more work than its allowance.
|
|
|
|
Run SSIM, training, and performance canaries separately. References must
|
|
match the effective GPU/runtime/attention backend; do not silently reuse
|
|
L40S performance results as GB200 baselines or reseed references as part of
|
|
routine CI. Workers keep W&B offline and disable reference publication.
|
|
|
|
Inspect the persistent ledger and recover an abandoned attempt with:
|
|
|
|
```bash
|
|
/opt/fastvideo-gpu-ci/venv/bin/python -I \
|
|
/opt/fastvideo-gpu-ci/source/scripts/gpu_ci/entrypoint.py status \
|
|
--config /etc/fastvideo-gpu-ci.json
|
|
|
|
/opt/fastvideo-gpu-ci/venv/bin/python -I \
|
|
/opt/fastvideo-gpu-ci/source/scripts/gpu_ci/entrypoint.py recover \
|
|
--config /etc/fastvideo-gpu-ci.json --build-id BUILD_ID.JOB_ID
|
|
```
|
|
|
|
Use the exact ledger ID from `status`; each Buildkite retry has a distinct
|
|
job ID. Recovery refuses a live coordinator, persists cancellation, stops
|
|
owned resources, and releases reservations only after confirming termination.
|
|
If creation or cleanup is ambiguous, investigate the recorded handle on its
|
|
backend and retain the reservation until the outcome is known. Do not delete
|
|
the database or manually zero counters to unblock the queue.
|
|
|
|
The dispatcher uploads controller logs, per-lane numeric results, request
|
|
metadata, and the suite summary to Buildkite. These are the sources for its
|
|
exit status. Generated videos and JUnit files stay in the worker unless a
|
|
dedicated Kubernetes artifact PVC is configured; automatic publication of
|
|
those worker files and Modal worker artifacts is not implemented. This is
|
|
a deployment limitation to account for before replacing existing artifact
|
|
review workflows.
|