Skip to content

Commit 5798720

Browse files
authored
Create README.md
1 parent 3c3e776 commit 5798720

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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

Comments
 (0)