πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Deployments intermediate ⏱ 15 minutes K8s 1.28+

Serverless Functions with WebAssembly

Build serverless functions using WebAssembly on Kubernetes with Fermyon Cloud, KEDA, and SpinKube. Achieve sub-millisecond scale-to-zero with Wasm cold starts.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: Build serverless functions using WebAssembly on Kubernetes with Fermyon Cloud, KEDA, and SpinKube. Achieve sub-millisecond scale-to-zero with Wasm cold starts.

The Problem

Traditional serverless on Kubernetes (Knative, OpenFaaS) still uses containers with 100ms+ cold starts. Scale-to-zero means users wait while containers pull images and initialize. WebAssembly changes this β€” Wasm modules start in under 1ms, making true instant scale-to-zero a reality.

The Solution

SpinKube + KEDA for Event-Driven Wasm Functions

# SpinApp with KEDA autoscaling β€” true scale-to-zero
apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
  name: webhook-handler
spec:
  image: ghcr.io/myorg/webhook-handler:v1
  replicas: 0                    # Start at zero!
  executor: containerd-shim-spin
  resources:
    limits:
      cpu: 100m
      memory: 64Mi
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: webhook-handler-scaler
spec:
  scaleTargetRef:
    apiVersion: core.spinoperator.dev/v1alpha1
    kind: SpinApp
    name: webhook-handler
  minReplicaCount: 0             # Scale to zero
  maxReplicaCount: 50
  cooldownPeriod: 30
  triggers:
    - type: prometheus
      metadata:
        serverAddress: http://prometheus.monitoring:9090
        metricName: http_requests_total
        query: sum(rate(http_requests_total{app="webhook-handler"}[1m]))
        threshold: "10"
    - type: kafka
      metadata:
        bootstrapServers: kafka.default:9092
        consumerGroup: webhook-handler
        topic: events
        lagThreshold: "5"

Build Serverless Functions with Spin

// src/lib.rs β€” A Spin HTTP function in Rust
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;

#[http_component]
fn handle_request(req: Request) -> anyhow::Result<impl IntoResponse> {
    let body = req.body();
    let event: serde_json::Value = serde_json::from_slice(body)?;
    
    // Process the webhook/event
    let response_body = format!(r#"{{"status":"processed","event_id":"{}"}}"#,
        event["id"].as_str().unwrap_or("unknown"));
    
    Ok(Response::builder()
        .status(200)
        .header("content-type", "application/json")
        .body(response_body)
        .build())
}
# spin.toml
spin_manifest_version = 2

[application]
name = "webhook-handler"
version = "1.0.0"

[[trigger.http]]
route = "/webhook"
component = "webhook-handler"

[component.webhook-handler]
source = "target/wasm32-wasi/release/webhook_handler.wasm"
allowed_outbound_hosts = ["https://api.example.com"]
key_value_stores = ["default"]
spin build
spin registry push ghcr.io/myorg/webhook-handler:v1

Function Patterns

# HTTP API function
apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
  name: api-function
spec:
  image: ghcr.io/myorg/api-function:v1
  replicas: 1
  executor: containerd-shim-spin
---
apiVersion: v1
kind: Service
metadata:
  name: api-function
spec:
  selector:
    core.spinoperator.dev/app-name: api-function
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-function
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-function
                port:
                  number: 80

Cold Start Comparison

PlatformCold StartImage PullTotal
AWS Lambda (container)200-500msN/A (cached)200-500ms
Knative (container)100-300ms2-10s (first)2-10s
OpenFaaS (container)100-200ms2-10s (first)2-10s
SpinKube (Wasm)<1ms<100ms<100ms
Fermyon Cloud (Wasm)<1msN/A<1ms
graph LR
    A[Event: HTTP / Kafka / Cron] --> B[KEDA Scaler]
    B --> C{Replicas = 0?}
    C -->|Yes| D[Scale 0β†’1 instantly]
    C -->|No| E[Route to existing pod]
    D --> F[Wasm cold start <1ms ⚑]
    F --> G[Process event]
    G --> H[Response]
    H --> I{Traffic stopped?}
    I -->|30s cooldown| J[Scale 1β†’0]

Common Issues

IssueCauseFix
Function can’t reach external APIsallowed_outbound_hosts not setAdd hosts to spin.toml
KEDA not scaling upMetrics query returns 0Test Prometheus query manually
Scale-to-zero not workingminReplicaCount > 0Set to 0 in ScaledObject
State lost between requestsWasm is stateless by defaultUse Spin key-value store or Redis

Best Practices

  • Use scale-to-zero for infrequent workloads β€” Wasm cold start makes it practical
  • Keep functions small and focused β€” one function per trigger
  • Use Spin key-value stores for session state, not in-memory variables
  • Set tight resource limits β€” 64Mi memory is generous for most Wasm functions
  • Use KEDA for event-driven scaling (Kafka, SQS, Prometheus metrics)

Key Takeaways

  • WebAssembly enables true instant scale-to-zero on Kubernetes
  • SpinKube + KEDA provides a complete serverless platform with <1ms cold starts
  • Wasm functions are 10-100x smaller and faster to start than container functions
  • WASI P2 enables full HTTP, key-value, and outbound networking support
  • Ideal for webhooks, API gateways, event processors, and edge functions
#wasm #serverless #keda #functions #scale-to-zero
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens