Skip to content

Deploying WebAssembly Microservices on Kubernetes - A Technical Deep Dive

Posted on:March 22, 2026 at 12:00 AM

Introduction

While Kubernetes was originally designed for container orchestration, the lightweight and efficient nature of WebAssembly creates new opportunities for deployment. This guide explores practical methods for deploying WebAssembly microservices on Kubernetes, examining different architectural approaches and their trade-offs.

Kubernetes and WebAssembly Integration

Current Integration Approaches

There are several ways to run WebAssembly workloads on Kubernetes:

  1. Container + Wasm Runtime - Package WebAssembly in containers
  2. Wasm-native runtimes - Using Kubernetes containerd plugins
  3. Hybrid deployments - Mix traditional and Wasm workloads
  4. Serverless platforms - Using Kubernetes-based Knative or OpenFaaS

Approach 1: Container-Wrapped WebAssembly

The most practical current approach is packaging WebAssembly modules in container images.

Architecture

Kubernetes Cluster
├── Pod A
│   └── Docker Container
│       ├── WebAssembly Runtime (Wasmer/WasmTime)
│       └── Wasm Module (application.wasm)
└── Pod B
    └── Docker Container
        ├── WebAssembly Runtime
        └── Wasm Module (application.wasm)

Dockerfile Example

FROM wasmerio/wasmer:latest

WORKDIR /app

# Copy your WebAssembly module
COPY ./target/wasm32-wasi/release/my_service.wasm .

# Copy the entrypoint script
COPY ./entrypoint.sh .
RUN chmod +x entrypoint.sh

# Expose the service port
EXPOSE 8080

# Run the WebAssembly module
ENTRYPOINT ["./entrypoint.sh"]

Kubernetes Deployment Definition

apiVersion: apps/v1
kind: Deployment
metadata:
  name: wasm-microservice
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: wasm-service
  template:
    metadata:
      labels:
        app: wasm-service
    spec:
      containers:
      - name: wasm-app
        image: registry.example.com/wasm-service:1.0.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 2
          periodSeconds: 5

Benefits:

Trade-offs:

Approach 2: Wasm Runtime with Containerd Plugin

More advanced setups use containerd plugins for native Wasm support.

Installation

# Install the containerd wasm shim
wget https://github.com/containerd/runwasi/releases/download/v0.5.0/containerd-shim-wasmtime-v1

# Place in containerd plugin directory
sudo mv containerd-shim-wasmtime-v1 /opt/containerd/bin/
sudo chmod +x /opt/containerd/bin/containerd-shim-wasmtime-v1

# Configure containerd
cat >> /etc/containerd/config.toml << EOF
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.wasmtime]
  runtime_engine = "/opt/containerd/bin/containerd-shim-wasmtime-v1"
  runtime_root = ""
  runtime_type = "io.containerd.runc.v2"
EOF

Pod Specification with Wasm Runtime

apiVersion: v1
kind: Pod
metadata:
  name: wasm-pod
spec:
  runtimeClassName: wasmtime
  containers:
  - name: wasm-app
    image: wasm-registry.example.com/app:latest
    resources:
      requests:
        memory: "32Mi"
        cpu: "50m"

Advantages:

Challenges:

Service Mesh Integration

Istio with WebAssembly

Integrate WebAssembly services with Istio service mesh:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: wasm-service-vs
spec:
  hosts:
  - wasm-service
  http:
  - match:
    - uri:
        prefix: "/api"
    route:
    - destination:
        host: wasm-service
        port:
          number: 8080
      weight: 100

Envoy Filter for Wasm

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: wasm-filter
spec:
  workloadSelector:
    labels:
      app: wasm-service
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.wasm
        typed_config:
          "@type": type.googleapis.com/udpa.type.v1.TypedStruct
          type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
          value:
            config:
              vm_config:
                runtime: envoy.wasm.runtime.wasmtime
                code:
                  local:
                    filename: /etc/envoy-wasm/filter.wasm

Multi-Service Orchestration

Service Discovery

Kubernetes service discovery works seamlessly with WebAssembly services:

apiVersion: v1
kind: Service
metadata:
  name: wasm-api-gateway
spec:
  type: LoadBalancer
  selector:
    app: wasm-gateway
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

StatefulSet for Wasm Services

For services requiring persistent state:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: wasm-stateful-service
spec:
  serviceName: wasm-stateful
  replicas: 3
  selector:
    matchLabels:
      app: wasm-state
  template:
    metadata:
      labels:
        app: wasm-state
    spec:
      containers:
      - name: wasm-app
        image: registry.example.com/wasm-stateful:1.0.0
        ports:
        - containerPort: 8080
          name: api
        volumeMounts:
        - name: data
          mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

Networking and Communication

Inter-Service Communication

WebAssembly services communicate via standard Kubernetes networking:

Service A (Wasm)
    │ HTTP/gRPC
    ├──→ Service B (Wasm)
    │     │
    │     └──→ Database

    └──→ Message Queue (RabbitMQ/Kafka)

Ingress Configuration

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wasm-services-ingress
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /orders
        pathType: Prefix
        backend:
          service:
            name: order-service-wasm
            port:
              number: 8080
      - path: /payments
        pathType: Prefix
        backend:
          service:
            name: payment-service-wasm
            port:
              number: 8080

Resource Management and Scaling

Horizontal Pod Autoscaling

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: wasm-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: wasm-microservice
  minReplicas: 2
  maxReplicas: 100
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

Resource Constraints

WebAssembly’s efficiency means you can set conservative resource limits:

resources:
  requests:
    memory: "32Mi"      # vs 128Mi for containers
    cpu: "50m"          # vs 200m for containers
  limits:
    memory: "64Mi"      # vs 512Mi for containers
    cpu: "200m"         # vs 1000m for containers

Monitoring and Observability

Prometheus Metrics

Expose Wasm service metrics:

// In your Wasm service
#[http::get("/metrics")]
fn metrics() -> String {
    format!(
        "# HELP requests_total Total HTTP requests\n\
         # TYPE requests_total counter\n\
         requests_total{{method=\"GET\"}} {}\n\
         requests_total{{method=\"POST\"}} {}",
        get_count, post_count
    )
}

ServiceMonitor for Prometheus

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: wasm-service-monitor
spec:
  selector:
    matchLabels:
      app: wasm-service
  endpoints:
  - port: metrics
    interval: 30s

Logging Configuration

apiVersion: v1
kind: ConfigMap
metadata:
  name: wasm-logging-config
data:
  fluent-bit.conf: |
    [INPUT]
        Name tail
        Path /var/log/containers/*wasm*.log
        Parser docker
        Tag kubernetes.*
    
    [FILTER]
        Name kubernetes
        Match kubernetes.*
    
    [OUTPUT]
        Name es
        Match kubernetes.*
        Host elasticsearch.logging
        Port 9200

Best Practices

1. Image Optimization

2. Security

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL
networkPolicy:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api-gateway

3. Performance Optimization

4. Deployment Strategy

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0  # Never go below desired replicas

Challenges and Solutions

ChallengeSolution
Image registry supportUse OCI-compliant registries or container wrappers
Cold startsPre-warm instances; use StatefulSets for persistent warm pools
DebuggingEnable tracing; use local development first
Dependency managementKeep Wasm modules self-contained; minimize external calls
MonitoringExport metrics compatible with Prometheus/Grafana

Future Directions

Conclusion

Deploying WebAssembly microservices on Kubernetes is increasingly practical and offers significant advantages in resource efficiency and performance. While the ecosystem is still maturing, organizations can already benefit from WebAssembly’s efficiency by using container wrappers or advanced Wasm runtime plugins.

The hybrid approach—mixing traditional containers and WebAssembly services—provides a pragmatic path forward for modernizing microservices infrastructures while maintaining compatibility with existing Kubernetes deployments.


Start small: Deploy a single WebAssembly service on Kubernetes today and experience the efficiency gains firsthand!