Production Readiness¶
What the cluster is already proven to do, and what is still on the hardening list.
Verified cluster behaviour¶
Every row below is asserted end-to-end against a live cluster with real models
over real HTTP — no mocks, no stubs. Run them with pytest tests/ -m
integration, or a single area via its own marker (e.g. -m blue_green).
| Capability | What the cluster guarantees | Proven by |
|---|---|---|
| Zero-downtime model cutover | Change a live model's config and the swap is atomic: traffic is hammered continuously through the cutover with zero failed requests, and the old deployment is fully torn down rather than left as a zombie | test_blue_green_integration.py |
| Load-driven autoscaling | Replicas scale out under sustained concurrency (bounded by max_replicas) and scale back to min_replicas once load stops — no errors on the way up or down |
test_autoscaling_integration.py |
| Multi-replica gateway convergence | With multiple gateway replicas, a deploy or removal converges on every replica — a removed model 404s on all of them instead of routing into a torn-down deployment | test_gateway_ha_integration.py |
| Engine crash recovery | SIGKILL the vLLM engine-core subprocess and the replica respawns and serves again on its own — no operator action, no cluster restart |
test_crash_recovery_integration.py |
| Authenticated node join / clean leave | A node joining with a missing or wrong token is rejected; with the right token it joins, and SIGTERM removes only that node — the head and its other nodes are untouched |
test_cluster_join.py |
| Fractional GPU multi-tenancy | Two different engines (vLLM at num_gpus: 0.6, llama-server at 0.3) share one physical GPU and serve concurrent traffic without starving each other |
test_fractional_gpu_sharing.py |
| Cross-process disconnect cancellation | A dropped client socket cancels in-flight inference across the Ray process boundary and frees the GPU; other requests on the same replica are unaffected | test_disconnect_integration.py |
| Per-identity prefix-cache isolation | An identical prompt from a different identity never hits another identity's KV-cache entry — the cross-tenant timing side channel is closed by construction | test_vllm_integration.py |
| Resumable background runs | A client can disconnect mid-stream; the run continues server-side and the client reconnects with starting_after to replay from where it left off through to completion |
test_responses_integration.py |
| Durable conversation state | Stored /v1/responses chains survive deletion of a parent turn, fan out into independent concurrent branches from one parent, and a cancel stays cancelled |
test_responses_integration.py |
| Server-side MCP tool loop | Real MCP server, discovered and called by the model — including the require_approval round trip, background mode, mid-flight cancel that sticks, and an unreachable server surfacing as a failed response rather than a 5xx |
test_mcp_integration.py |
| Real in-replica concurrency | llama-server parallel slots serve concurrent requests genuinely in parallel — N at once complete in well under N× the single-request time, not serialized behind a lock |
test_llama_server_integration.py |
| Hot reconcile of the model set | The entire integration suite swaps the deployed model set repeatedly via --reconcile against one long-lived gateway process that is never restarted |
conftest.py |
| Cross-loader pipelines | TTS audio generated by one deployment is fed straight back in as STT input to another, through the same gateway | test_audio_integration.py |
Alongside these, a cluster-wide deploy coordinator serializes model loads so a
tight-on-VRAM cluster never loads two models concurrently, and /v1/responses
passes the independent Open Responses
compliance suite 17/17.
Hardening roadmap¶
Remaining work, organized by severity and area. The Kubernetes/KubeRay path is
the current focus — a Helm chart ships in
helm/modelship,
with GPU-aware probes and gateway-level rate limiting next.
Critical (Must Have Before Production)¶
Security¶
- [x] API authentication layer — API key auth at the gateway level via
MSHIP_API_KEYSenv var; OpenAI-compatibleAuthorization: Bearer <key>header - [ ] Rate limiting — per-user/IP/model throttling to prevent GPU resource monopolization
- [x] Input size limits — coarse payload size limit at the gateway (
MSHIP_MAX_REQUEST_BODY_BYTES, default 50 MB) - [ ] Per-model context validation — no loader validates a request's prompt length against the model's context before inference
- [ ] Lock down CORS — replace wildcard
*origins with environment-specific allowed origins
Health & Readiness¶
- [x] Detailed readiness probe —
/readyzreturns 200 only when every expected model is registered with the gateway; 503 with loaded/pending lists while loading./healthstays as a cheap liveness endpoint. Per-model load times and total time-to-ready are exposed via/readyzfor observability. - [ ] Model-specific health checks — per-model liveness status (vLLM engine, Ray actor state)
- [ ] GPU memory checks — detect and report memory pressure before OOM
Testing¶
- [x] API endpoint tests — HTTP-level tests for all
/v1/endpoints (viatests/test_*_integration.py) - [x] Integration tests — actual model loading and inference (using Qwen-0.5B/0.6B)
- [x] Streaming tests — SSE streaming correctness and error handling
- [ ] Error recovery tests — simulate failures and verify behavior
High Priority (Should Have)¶
Deployment & Infrastructure¶
- [x] Kubernetes manifests — KubeRay
RayCluster+RayJob, gatewayService, modelsConfigMap, cachePVC, secrets, optionalPodMonitor(via the Helm chart inhelm/modelship), with resource requests/limits, GPU scheduling, node affinity, and tolerations per worker group - [x] Helm chart — parameterized deployment in
helm/modelship(see its README) - [x] Simpler non-K8s deployment — reframed from "Docker Compose", which orchestrates a single host and can't form a cluster across VMs. Supported path is own-head/join
docker run(see docs/multi-node-docker.md): a few VMs, no orchestrator, joined into one Ray cluster via--address/--token. Compose remains a possible single-host wrapper around single-container mode, not planned work. - [x] Liveness/readiness probes in container spec — KubeRay gates each Ray pod on a Serve proxy
/-/healthzcheck (via the namedserveport);/readyzreturns 503 until all models load, suitable for an external LB/Ingress health check
Alerting & Observability¶
- [x] Prometheus alerting rules — error rate thresholds, latency P99 breaches, model load failures, GPU memory pressure (see
docs/prometheus-alerts.yml) - [ ] SLO/SLI definitions — define target availability and latency for each endpoint type
- [x] Structured logging (JSON) —
MSHIP_LOG_FORMAT=jsonfor log aggregation (ELK/Loki/Splunk) - [x] Request-ID correlation — trace a request from gateway through Ray actor boundaries via
contextvars - [x] Log level configuration —
MSHIP_LOG_LEVELcontrols app logs;TRACEenables library debug logs - [x] Syslog support —
--log-target syslog://host:portships logs to a remote syslog server (UDP or TCP) - [x] OpenTelemetry log export —
--otel-endpointships logs (and enables Ray traces) via OTLP to any OTel collector
Resilience¶
- [x] Head-node HA (GCS fault tolerance) — the chart backs Ray's GCS with Redis (
gcsFaultToleranceOptions,redis.addressrequired): a restarted head pod recovers cluster state, workers + model actors survive. The same Redis backs the modelship state store (redis://), so the deploy coordinator's routing registry survives head/coordinator death and the gateway self-heals routing on recovery (coordinator runsmax_restarts=-1) - [ ] Ray actor restart policies — auto-restart crashed model actors
- [ ] Circuit breaker — stop routing to a failing model after N consecutive errors
- [ ] Backpressure / queue depth limits — reject requests when queue is saturated instead of unbounded queuing
- [ ] Graceful shutdown timeout — add timeout wrapper around
serve.shutdown()to prevent hanging - [ ] GPU OOM recovery — detect and recover from GPU memory exhaustion
Update Strategy¶
- [ ] Rolling update support — configure Ray Serve's built-in rolling updates for zero-downtime deploys
- [x] Per-model autoscaling —
autoscaling_config(min/max replicas, target ongoing requests, up/downscale delays; scale-to-zero supported) scales replica count with load instead of a fixednum_replicas - [x] Gateway HA —
MSHIP_GATEWAY_REPLICAS > 1runs multiple gateway replicas; routing tables stay consistent via the deploy coordinator's watch loop, and a Serve proxy on every node lets the gateway Service survive single-pod loss - [x] Self-heal after cluster loss — each deploy persists this gateway's effective config + routing registry to the configured state store (
MSHIP_STATE_STORE:redis://, which the chart always sets; thememory://default is cluster-scoped but dies with the cluster). With Redis the gateway self-heals automatically on a head restart; after a full cluster lossmship deploy --reconcile(no--config, run viahelm upgrade) replays the recorded set - [x] Model hot-reload — allow
models.yamlchanges without full server restart (viamship deploy --reconcile) - [x] Changelog — track breaking changes between versions
- [x] Migration guide — document config format changes between versions
Medium Priority (Nice to Have)¶
CI/CD Hardening¶
- [ ] Security scanning — Trivy for Docker images, dependency vulnerability checks
- [ ] SBOM generation — Software Bill of Materials for supply chain visibility
- [ ] Multi-arch builds — ARM64 support alongside AMD64
- [ ] Performance benchmarks in CI — detect throughput/latency regressions
Operations¶
- [ ] Secrets management integration — document Vault / K8s Secrets / sealed-secrets usage for
HF_TOKENand future API keys - [ ] Troubleshooting runbook — common failure modes and resolution steps for on-call
- [ ] Capacity planning guide — estimate concurrent users per GPU setup per model mix
- [ ] GPU memory budgeting guide — model co-location recommendations to avoid fragmentation
- [x] Multi-node Ray cluster setup docs — head + worker topology, multi-node ingress, cache PVC access modes, and self-heal documented in the Helm chart README (
helm/modelship/README.md) - [ ] Request audit trail — persistent log of requests for compliance/debugging
Documentation¶
- [ ] OpenAPI/Swagger spec — formal API reference for consumers
- [ ] Performance tuning guide — vLLM engine kwargs, batch sizes, KV cache sizing
- [ ] Blue-green / canary deployment patterns — documented strategies for safe rollouts
- [ ] Model pre-warming — mechanism to pre-download and cache models before deploy, reducing cold start from minutes to seconds
Current Scorecard¶
| Area | Current | Target |
|---|---|---|
| Architecture & Design | 9/10 | 9/10 |
| Monitoring (metrics) | 9/10 | 9/10 |
| Monitoring (alerting + logs) | 9/10 | 9/10 |
| Security | 4/10 | 8/10 |
| Resilience | 8/10 | 8/10 |
| Testing | 8/10 | 9/10 |
| DevOps Experience | 8/10 | 8/10 |
| Update/Deploy Strategy | 7/10 | 7/10 |