WASM Inside the Pod: Running WebAssembly Workloads with Container Tooling on Kubernetes

WASM Inside the Pod describes a modern approach to running WebAssembly workloads in Kubernetes — combining fast, secure wasm modules with container tooling and CRI runtimes to deliver instant-start microservices. This practical guide walks through compiling a wasm module, packaging it with BuildKit into an OCI image, wiring it to a CRI-aware runtime on Kubernetes, and applying operational best practices for security, observability, and rapid starts.

Why run WebAssembly in Kubernetes pods?

WebAssembly offers strong sandboxing, small binary footprints, and near-native performance for many use cases. When combined with Kubernetes and container tooling you get: instant cold-starts for edge/microservices, consistent OCI-based delivery, and fine-grained resource isolation that complements existing container infrastructure.

Step 1 — Build: compiling a WASM module

Choose the language and toolchain that best fits your service. Common options include Rust (wasm32-wasi), TinyGo, and AssemblyScript. The goal is a single .wasm artifact targeting WASI or the runtime ABI your cluster uses.

Rust (recommended for mature workloads)

Example commands:

rustup target add wasm32-wasi
cargo build --target wasm32-wasi --release
# output: target/wasm32-wasi/release/my_service.wasm

TinyGo (fast, small binaries)

tinygo build -o my_service.wasm -target wasi ./cmd/my_service

AssemblyScript (TypeScript-to-wasm)

npm install -g assemblyscript
asc assembly/index.ts -b my_service.wasm -O3

Tip: keep the WASM module minimal (single responsibility) and optimize for size and startup latency (strip debug, use -O3 or equivalent).

Step 2 — Package: BuildKit + OCI image for wasm

Package your .wasm into an OCI image so it can be stored in registries and deployed via regular Kubernetes primitives. BuildKit (buildctl) is ideal because it supports efficient caching and multi-stage workflows.

Minimal Dockerfile for a wasm OCI image

FROM scratch
# Copy the wasm module into the image
COPY my_service.wasm /app/my_service.wasm
# Optional: metadata label for tooling
LABEL io.wasm.runtime="wasi"
# Image does not run like a normal container; runtime shim will execute the .wasm

Build and push with BuildKit (example):

buildctl build \
  --frontend dockerfile.v0 \
  --local context=. \
  --local dockerfile=. \
  --output type=registry,ref=registry.example.com/team/my-service:wasm

Notes:

  • Use OCI labels/annotations to declare the module ABI (e.g., wasi) and required capabilities.
  • Enable BuildKit cache exports to speed CI builds.
  • Sign images with Sigstore/cosign for supply-chain trust before pushing.

Step 3 — Runtime: CRI runtimes and RuntimeClass

Kubernetes schedules pods to nodes; to execute a wasm image you need a node with a CRI runtime or Krustlet that knows how to run wasm modules. Options include containerd’s wasm shims, WasmEdge, Wasmtime-based shims, or Krustlet (a kubelet that supports WebAssembly).

RuntimeClass and Pod manifest

Create a RuntimeClass on clusters where containerd/CRI has been configured to route to the wasm runtime shim. Then set runtimeClassName on pods to target wasm execution nodes.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: wasm
handler: io.containerd.runtimes.wasm.v1
---
apiVersion: v1
kind: Pod
metadata:
  name: my-service-wasm
spec:
  runtimeClassName: wasm
  containers:
  - name: my-service
    image: registry.example.com/team/my-service:wasm
    # The CRI shim will execute /app/my_service.wasm according to its configuration
    resources:
      requests:
        cpu: "50m"
        memory: "64Mi"
      limits:
        cpu: "200m"
        memory: "128Mi"
  nodeSelector:
    kubernetes.io/arch: wasm32-wasi

If using Krustlet, the pod is scheduled to nodes where krustlet runs; krustlet will fetch the OCI image and run the wasm module with the configured runtime (Wasmtime, WasmEdge).

Step 4 — Orchestration and operational tips

  • Health probes: implement a tiny HTTP or readiness endpoint inside your small host shim or use sidecar probing to validate module liveness.
  • Observability: export metrics via a lightweight sidecar or integrate with host-level observability that understands wasm ABI (logs, traces).
  • Security: enforce minimal capabilities, disallow hostPath and privileged: true, and use PodSecurityPolicies or OPA/Gatekeeper to restrict wasm images.
  • Network: rely on CNI as usual; if using service mesh, confirm mesh supports wasm or run the wasm module behind a standard sidecar proxy.
  • Scaling: because wasm cold-start is small, horizontal scaling is efficient — tune HPA thresholds for low-latency scaling.

Best practices

  • Small modules: keep each wasm microservice focused and under 1-2MB if possible to maximize startup and network transfer speed.
  • OCI metadata: annotate images with ABI, version, and required capabilities to help admission controllers and runtimes make safe decisions.
  • CI/CD: use BuildKit in CI, cache layers, and verify signatures with cosign before deployment.
  • Runtime parity: standardize on one runtime (e.g., Wasmtime or WasmEdge) for predictable behavior across environments.
  • Policy and attestation: use Sigstore and supply-chain scanning to validate module provenance and integrity.

Common troubleshooting

If your pod stays in Pending or CrashLoopBackOff:

  • Verify that the node targeted by the scheduler actually runs the wasm-enabled CRI (check runtimeClass handler mapping).
  • Inspect the node runtime logs (containerd/krustlet) to see wasm shim errors when fetching or executing the module.
  • Confirm the module targets the correct ABI (WASI vs. a runtime-specific ABI) and that required imports are provided.

WASM Inside the Pod unlocks a compelling middle ground: the operational maturity and delivery model of OCI images and Kubernetes with the performance and security isolation of WebAssembly. With BuildKit for efficient builds, OCI packaging for distribution, and a CRI-capable runtime or Krustlet to execute modules, teams can deploy ultra-fast, secure microservices across cloud and edge.

Conclusion: Adopt a minimal, signed WASM artifact workflow — compile for WASI, package with BuildKit into OCI images, configure a RuntimeClass for your wasm CRI, and apply strict security policies for safe, instant-start microservices.

Try it now: build a tiny Rust or TinyGo wasm module, package with BuildKit, and deploy to a wasm-enabled node to experience sub-second starts and strong sandboxing.