The Problem With Container Cold Starts
You've felt it. You scale a Deployment from 0 → 1, and for 300ms to 2 seconds, your pod is in ContainerCreating. At 10k concurrent requests, that's not a blip — it's a latency cliff.
WebAssembly solves this at the runtime level: single-digit millisecond cold starts, ~2 MB memory per instance (vs. 100+ MB for a typical container), and a capability-based security model that's sandboxed by default.
The question was never should we run Wasm on Kubernetes. The question was how, without breaking everything we already have.
SpinKube is the answer.
What Is SpinKube?
SpinKube is a CNCF Sandbox project (accepted January 2025) that makes WebAssembly a first-class workload in Kubernetes. It's built on the Spin framework (also CNCF Sandbox) and is written in Rust.
The key insight: no new API, no new scheduler, no parallel platform. SpinKube plugs into the existing containerd → CRI → RuntimeClass path. Your Wasm app gets scheduled with the same kubectl apply, the same HPA, the same service mesh, the same GitOps pipeline.
Fun fact: SpinKube was originally created by Fermyon. When Akamai acquired Fermyon in December 2025, the project was already safely under CNCF governance — a structural guarantee that outlasts any single company's roadmap.
GitHub: github.com/spinframework/spinkube (migrated from the spinkube org during CNCF onboarding)
Stars: 6,200+ · Contributors: 80+ · License: Apache 2.0
Architecture at a Glance
┌─────────────────────────────────────────────────────────┐
│ Your SpinApp YAML │
│ (kubectl apply -f spinapp.yaml) │
└──────────────────────┬──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ spin-operator (Kubebuilder operator) │
│ • Watches SpinApp CRD │
│ • Creates Deployment + Service │
│ • Sets runtimeClassName: wasmtime-spin-v2 │
└──────────────────────┬──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ Kubernetes Scheduler │
│ • Standard constraints + RuntimeClass selector │
│ • Places pod on nodes with the Spin shim installed │
└──────────────────────┬──────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ containerd │
│ • Sees runtimeClassName → routes to containerd-shim-spin│
│ • Shim launches Wasmtime (or Wasmer/WasmEdge) │
│ • Wasm module executes — no runc, no OCI container │
└─────────────────────────────────────────────────────────┘
Three components you actually interact with:
| Component | Role |
|---|---|
spin-operator |
CRD + controller. Turns SpinApps into Deployments. |
containerd-shim-spin |
The runtime. Replaces runc for Wasm pods. Built on runwasi. |
runtime-class-manager |
Auto-installs and manages the shim across your node pool. Replaces the old KWasm operator. |
Prerequisites
- Kubernetes 1.27+ (k3s, kind, EKS, GKE, AKS all work)
-
containerdas the container runtime (not Docker) - Spin CLI installed locally
- A Wasm-compatible language toolchain (Rust, Go, JavaScript, Python, C#)
Step 1: Install SpinKube on Your Cluster
For a quick test on kind or k3s:
# Install the Runtime Class Manager (manages shim lifecycle)
helm repo add spinkube https://spinkube.github.io/charts
helm install runtime-class-manager spinkube/runtime-class-manager \
--namespace spinkube-system --create-namespace
# Install the Spin Operator
helm install spin-operator spinkube/spin-operator \
--namespace spinkube-system
The Runtime Class Manager will:
- Label nodes that support the Spin runtime
- Install
containerd-shim-spinon those nodes - Create the
RuntimeClassresource (wasmtime-spin-v2)
Verify:
kubectl get runtimeclass
# NAME HANDLER
# wasmtime-spin-v2 spin
kubectl get nodes -l spinkube.io/runtime=wasmtime-spin-v2
Step 2: Build a Spin App
Create a new Spin project (Rust example):
spin new my-wasm-app --language rust
cd my-wasm-app
spin-new generates a minimal HTTP handler. Edit src/main.rs:
use spin_sdk::http::{Request, Response};
#[http_component]
pub fn handle(req: Request) -> Response {
let name = req.uri().path().trim_start_matches('/');
Response::ok(format!("Hello, {name}! (served by Wasm on K8s)"))
}
Build and package:
spin build
# Produces: target/wasm32-wasi/release/my-wasm-app.wasm
The output is a ~2 MB Wasm binary — compared to a ~100 MB+ OCI image for an equivalent Rust HTTP server.
Step 3: Deploy to Kubernetes
Create spinapp.yaml:
apiVersion: spinkube.dev/v1alpha1
kind: SpinApp
metadata:
name: my-wasm-app
namespace: default
spec:
replicas: 3
image: ghcr.io/yourorg/my-wasm-app:latest # Push your Spin app to any OCI registry
runtime: wasmtime-spin-v2
port: 80
resources:
requests:
memory: "4Mi"
cpu: "10m"
limits:
memory: "32Mi"
cpu: "100m"
Apply:
kubectl apply -f spinapp.yaml
The spin-operator reconciles this into a standard Deployment with runtimeClassName: wasmtime-spin-v2. Watch it go:
kubectl get pods -w
# my-wasm-app-7f8b4c6d2-x1k9p 1/1 Running 0 3s
# my-wasm-app-7f8b4c6d2-m2n8q 1/1 Running 0 3s
# my-wasm-app-7f8b4c6d2-p3o7r 1/1 Running 0 3s
~3 seconds from kubectl apply to all pods Running. Compare that to a typical containerized app pulling a 150 MB image.
Step 4: Verify It Works
Create a Service and hit it:
kubectl expose deployment my-wasm-app --port=80 --type=NodePort
kubectl get svc my-wasm-app -o wide
Then:
curl http://<node-ip>:<port>/world
# Hello, world! (served by Wasm on K8s)
Step 5: Scale It (The Fun Part)
kubectl scale spinapp my-wasm-app --replicas=100
100 Wasm instances. Total memory: ~200 MB (vs. ~10 GB for 100 containerized instances of the same app).
Add an HPA for autoscaling:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-wasm-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-wasm-app
minReplicas: 3
maxReplicas: 200
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
Or use KEDA for event-driven scaling (queue depth, HTTP request rate). SpinKube integrates with KEDA out of the box.
Step 6: Observe It
SpinKube exports metrics to OpenTelemetry. Point your OTel collector at the pods and you get traces in Jaeger, metrics in Prometheus — same as any other K8s workload.
As of early 2026, SpinKube also supports Gateway API for ingress, so your Wasm apps sit behind the same API Gateway as your containerized services.
Containers vs. Wasm on SpinKube: The Honest Comparison
| Dimension | Container (runc) | Wasm (SpinKube) |
|---|---|---|
| Cold start | 100 ms – 2 s | 1–10 ms |
| Idle memory | 50–500 MB | 2–30 MB |
| Artifact size | 100 MB – 2 GB | 1–10 MB |
| Security model | Namespace + cgroups (OS-level) | Capability-based (WASI) — no file/network access unless explicitly granted |
| Full OS access | ✅ | ❌ (no raw sockets, no threads in WASI 0.2) |
| Scheduling | Standard |
Identical (same kubectl apply) |
| Best for | Stateful, long-lived, OS-dependent services | Stateless, I/O-light, high-frequency handlers |
They coexist. Run your Postgres and your message queue as containers. Run your API gateway, request transformers, and edge functions as Wasm. Same cluster, same namespace, same tooling.
When SpinKube Makes Sense (and When It Doesn't)
✅ Use SpinKube when:
- You have short-lived, stateless HTTP handlers (edge functions, API transforms, auth checks)
- Cold start latency is a real problem (serverless patterns, bursty traffic)
- You want to pack more workloads per node (density = cost savings)
- You need a smaller attack surface (WASI capability model)
❌ Skip SpinKube when:
- Your workload needs full OS access (raw sockets, FUSE, GPU drivers)
- It's a long-lived stateful service (database, cache)
- Your language/toolchain can't target
wasm32-wasi - You're in a Docker-only environment (SpinKube requires containerd)
What's Missing (and Where Funding Helps)
SpinKube is in CNCF Sandbox — the earliest maturity level. That means:
- 13 maintainers (6 from Fermyon/Akamai, 3 from Microsoft, 1 each from SUSE, Liquid Reply, Hetzner, independent) — a small team for a project this central to the Wasm-on-K8s story.
- Roadmap items still open: automatic OpenTelemetry instrumentation for Wasm apps, more mature multi-runtime support, Windows node support, and a formal security audit.
- Docs and tutorials are good but thin compared to, say, Helm or KEDA. The community needs more "I built X with SpinKube" content.
- No LFX Crowdfunding campaign is active yet. The project could use funding for: CI infrastructure, conference travel (KubeCon, Wasm I/O), a part-time community manager, and a security audit.
If you found this guide useful and want to see SpinKube move to Incubating, the most impactful things you can do:
- Contribute — even docs, bug reports, and test cases count. GitHub
- Use it in production and share your experience (a Dev.to post, a talk, a blog).
- Support CNCF funding efforts — when the project launches an LFX Crowdfunding campaign, it'll be listed on the CNCF funding page.
- Join the community — SpinKube Slack (via CNCF Slack) is where decisions happen.
TL;DR
| Fact | Detail |
|---|---|
| What | CNCF Sandbox project for running Wasm on Kubernetes |
| How | containerd shim + RuntimeClass — no new API |
| Cold start | 1–10 ms |
| Memory | ~2 MB per instance |
| Languages | Rust, Go, JS, Python, C# (anything that targets wasm32-wasi) |
| Runtimes | Wasmtime (default), Wasmer, WasmEdge |
| Maturity | Sandbox (accepted Jan 2025) |
| GitHub | spinframework/spinkube |
| License | Apache 2.0 |
What's your experience with Wasm on Kubernetes? Have you tried SpinKube in production? Drop your setup in the comments — I'm especially curious about anyone running it alongside KEDA or Gateway API.
If you want to support the project, the best thing you can do right now is **contribute* or write about your experience. The CNCF funding infrastructure is there and ready when the project is ready to use it.*
Top comments (0)