|
| 1 | +# vllm-coldstart-operator |
| 2 | + |
| 3 | +A Kubernetes operator, written in Rust with [kube-rs](https://kube.rs/), that manages vLLM inference replicas and treats **cold start as a first-class signal** rather than an invisible side effect of pod startup. |
| 4 | + |
| 5 | +Kubernetes decides a pod is ready when its process is up. For an LLM inference server that is the wrong moment: the process is alive, but it still has to load weights and warm up before it can serve a token. This operator models that gap explicitly — a `VllmService` is `Ready` only when it is *warm and able to serve*, not merely running. |
| 6 | + |
| 7 | +The operator is the operational half of a pair of profiling tools: |
| 8 | + |
| 9 | +- [vllm-coldstart-probe](https://github.com/MicheleCampi/vllm-coldstart-probe) — an eBPF profiler that **measures** where vLLM cold start goes (syscalls, libcuda, GPU warmup). |
| 10 | +- **vllm-coldstart-operator** (this repo) — **acts** on that knowledge inside a cluster. |
| 11 | + |
| 12 | +## What it does |
| 13 | + |
| 14 | +The operator introduces a `VllmService` custom resource: |
| 15 | + |
| 16 | +```yaml |
| 17 | +apiVersion: inference.michelecampi.dev/v1alpha1 |
| 18 | +kind: VllmService |
| 19 | +metadata: |
| 20 | + name: qwen-7b |
| 21 | +spec: |
| 22 | + model: "Qwen/Qwen2.5-7B-Instruct" |
| 23 | + replicas: 1 |
| 24 | + warmupStrategy: Eager # Eager | Graph |
| 25 | +``` |
| 26 | +
|
| 27 | +For each `VllmService`, the controller: |
| 28 | + |
| 29 | +- **Reconciles an owned Deployment** via idempotent server-side apply. The Deployment carries an owner reference, so deleting the `VllmService` garbage-collects it automatically — no manual cleanup code. |
| 30 | +- **Maps `warmupStrategy` to pod configuration.** `Eager` requests `enforce_eager` (faster cold start, slower steady state — better for scale-to-zero); `Graph` leaves CUDA graphs on (slower cold start, faster steady state). This is the operational lever behind the probe's finding that CUDA graphs make cold start ~3x slower. |
| 31 | +- **Derives a cold-start-aware lifecycle phase** from the Deployment's ready replicas and writes it to the `VllmService` `/status` subresource: |
| 32 | + - `Pending` — Deployment created, no replica ready yet |
| 33 | + - `Warming` — some replicas ready, not all (process up, warming up) |
| 34 | + - `Ready` — all desired replicas ready (warm and able to serve) |
| 35 | + |
| 36 | +Writing on the status subresource does not retrigger the spec watcher, so there is no reconcile loop. |
| 37 | + |
| 38 | +## Architecture |
| 39 | + |
| 40 | +``` |
| 41 | +src/lib.rs VllmService CRD (spec + status), phase_for() lifecycle logic, unit tests |
| 42 | +src/main.rs controller: reconcile loop, Deployment apply, status patch |
| 43 | +src/bin/crdgen.rs emits the CRD YAML (cargo run --bin crdgen) |
| 44 | +deploy/crd.yaml generated CRD |
| 45 | +deploy/examples/ sample VllmService |
| 46 | +``` |
| 47 | +
|
| 48 | +The controller watches `VllmService` resources and `.owns()` the Deployments it creates, so changes to either retrigger reconciliation. Built on kube-rs 2.x, k8s-openapi 0.26 (Kubernetes 1.34 API), Rust edition 2021, MSRV 1.83. |
| 49 | +
|
| 50 | +## Try it locally |
| 51 | +
|
| 52 | +Requires Docker, [kind](https://kind.sigs.k8s.io/), `kubectl`, and a Rust toolchain. |
| 53 | +
|
| 54 | +```bash |
| 55 | +# 1. Create a local cluster |
| 56 | +kind create cluster --name operator-dev |
| 57 | +
|
| 58 | +# 2. Install the CRD |
| 59 | +cargo run --bin crdgen > deploy/crd.yaml |
| 60 | +kubectl apply -f deploy/crd.yaml |
| 61 | +
|
| 62 | +# 3. Run the operator (talks to the cluster via your kubeconfig) |
| 63 | +cargo run --bin vllm-coldstart-operator |
| 64 | +
|
| 65 | +# 4. In another shell, create a VllmService and watch the lifecycle |
| 66 | +kubectl apply -f deploy/examples/qwen-7b.yaml |
| 67 | +kubectl get vllmservice qwen-7b -o jsonpath='{.status.phase}: {.status.message}' |
| 68 | +# Pending -> ... -> Ready: 1/1 replicas ready and warm |
| 69 | +
|
| 70 | +# 5. Delete it and watch the Deployment garbage-collect |
| 71 | +kubectl delete vllmservice qwen-7b |
| 72 | +kubectl get deployment qwen-7b # NotFound |
| 73 | +``` |
| 74 | + |
| 75 | +## What is real and what is a placeholder |
| 76 | + |
| 77 | +This is honest about its boundaries, because the value is in the control plane, not a staged demo. |
| 78 | + |
| 79 | +**Real and exercised:** the control plane. The reconcile loop, owned-Deployment management, server-side apply, owner-reference garbage collection, and the cold-start-aware status machine are real and verified end-to-end against a live cluster (see CI below). |
| 80 | + |
| 81 | +**Placeholder:** the data plane. On a CPU-only kind cluster you cannot run real vLLM, so the managed pod uses `registry.k8s.io/pause:3.10` as a documented stand-in, and `warmupStrategy` is recorded as an environment variable rather than driving a real vLLM flag. Turning this into a real deployment is a matter of swapping the container image for a vLLM serving image and adding a GPU resource request — the lifecycle logic does not change. That substitution, and validating the `Warming -> Ready` transition against real measured cold start, is the next step on the roadmap. |
| 82 | + |
| 83 | +## Testing & CI |
| 84 | + |
| 85 | +- **Unit tests** on `phase_for()`, the lifecycle-derivation logic (the core cold-start decision), covering each phase transition and edge cases. |
| 86 | +- **End-to-end CI** ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)) runs on every push: one job for `fmt --check` + `clippy` + `test` + release build (with `-D warnings`), and a second job that spins up an ephemeral kind cluster, installs the CRD, runs the operator, applies a `VllmService`, and asserts the full lifecycle — Deployment created, status reaches `Ready`, owner reference set, Deployment garbage-collected on delete. Waits use bounded polling, not fixed sleeps, so the test asserts convergence without being timing-flaky. |
| 87 | + |
| 88 | +## Roadmap |
| 89 | + |
| 90 | +- Make the profiling-informed decision explicit in status — e.g. surface the expected cold-start cost per `warmupStrategy`, derived from the probe's measurements. |
| 91 | +- Run against real vLLM on a GPU cluster and validate that `Warming -> Ready` tracks the measured cold start. |
| 92 | +- Capstone write-up linking the probe and the operator: measuring cold start, then acting on it. |
| 93 | + |
| 94 | +## License |
| 95 | + |
| 96 | +Apache-2.0 |
0 commit comments