tutorial

Monitoring runwasi with Vigilmon: Keeping Your WebAssembly Kubernetes Workloads Running

How to monitor runwasi with Vigilmon — tracking containerd shim availability, Wasm module execution health, WASI runtime liveness, and Kubernetes pod scheduling for WebAssembly workloads.

runwasi is a containerd shim that enables Kubernetes to schedule WebAssembly workloads as native pods using WASI (WebAssembly System Interface). It bridges the containerd runtime interface with Wasm runtimes like Wasmtime, WasmEdge, and Wasmer, allowing platform teams to run Wasm modules alongside OCI container workloads on the same cluster. When runwasi shims are unavailable or misconfigured, Wasm pods fail to schedule silently — they queue indefinitely or crash with cryptic CRI errors while OCI workloads on the same node continue running fine. Vigilmon gives you external monitoring that watches the runwasi shim layer and validates that Wasm pod lifecycle operations are completing on schedule.

What You'll Build

  • Vigilmon HTTP monitors for the containerd runtime class health endpoint
  • A heartbeat monitor validating that Wasm pods schedule and execute end-to-end
  • A WASI runtime availability heartbeat to catch shim process failures
  • Alert channels routed to your platform engineering team

Prerequisites

  • runwasi installed as a containerd shim (e.g., containerd-shim-wasmtime-v1)
  • Kubernetes RuntimeClass configured for your Wasm runtime
  • A free account at vigilmon.online

Why Monitoring runwasi Matters

runwasi operates at a layer that most Kubernetes observability tools miss. Its failure modes are invisible to workload-level monitoring and are easy to attribute to unrelated causes:

Shim process registration failures prevent Wasm pods from ever starting. When containerd tries to hand off a Wasm pod to the runwasi shim, it looks for a binary matching the shim name in the PATH (e.g., containerd-shim-wasmtime-v1). If the binary is missing, wrong version, or has a broken dependency on a system WASI runtime, the pod enters CreateContainerError with a non-obvious message. Kubernetes schedulers don't distinguish between a broken shim and a resource constraint — pods may be retried indefinitely.

Runtime class misconfiguration is a silent failure. If the Kubernetes RuntimeClass object references a handler that doesn't match the installed shim name, Wasm pods are admitted but never scheduled on nodes that lack the matching handler. Pods queue in Pending state forever. Without an end-to-end lifecycle probe, this misconfiguration persists for days in multi-tenant clusters where developers assume the problem is quota.

WASI module execution failures occur when the Wasm binary is valid but the WASI interface version expected by the module doesn't match the runtime version provided by runwasi's backing engine. Pods start and immediately exit with a non-zero code. If your alerting only watches for CrashLoopBackOff (which requires multiple restarts), first-crash failures go undetected for the TTL of the failed pod object.

Node-level shim drift happens after node upgrades. A containerd upgrade on a node may reset the shim configuration, removing runwasi from the runtime map. Wasm pods that were running on that node are evicted and rescheduled — but if every node has been upgraded, no node accepts the Wasm RuntimeClass and the workload disappears silently.


Step 1: Monitor containerd Shim Registration

Verify the runwasi shim binary is installed and registered with containerd:

# Verify shim binary exists and is executable
ls -la /usr/local/bin/containerd-shim-wasmtime-v1
# or
ls -la /usr/local/bin/containerd-shim-wasmedge-v1

# Verify containerd sees the shim
ctr plugins ls | grep -i wasm
# Expected: io.containerd.runtime.v2.task  wasmtime  linux/amd64  ok

Expose a lightweight health endpoint for Vigilmon to poll:

# /usr/local/bin/runwasi-health-server.sh
#!/bin/bash
# Returns 200 if the wasmtime shim is installed; 503 otherwise
while true; do
  if command -v containerd-shim-wasmtime-v1 >/dev/null 2>&1 && \
     ctr plugins ls 2>/dev/null | grep -q wasmtime; then
    STATUS="200 OK"
    BODY='{"status":"ok","shim":"wasmtime"}'
  else
    STATUS="503 Service Unavailable"
    BODY='{"status":"error","shim":"wasmtime"}'
  fi
  printf "HTTP/1.1 %s\r\nContent-Type: application/json\r\n\r\n%s" \
    "$STATUS" "$BODY" | nc -l -p 9102 -q 1
done
# /etc/systemd/system/runwasi-health.service
[Unit]
Description=runwasi health endpoint
After=containerd.service

[Service]
ExecStart=/usr/local/bin/runwasi-health-server.sh
Restart=always

[Install]
WantedBy=multi-user.target
chmod +x /usr/local/bin/runwasi-health-server.sh
systemctl enable --now runwasi-health

In the Vigilmon dashboard:

  1. Go to Add Monitor → HTTP
  2. Configure:

| Field | Value | |---|---| | Name | runwasi shim registration | | URL | http://your-node-ip:9102 | | Method | GET | | Expected status | 200 | | Response body contains | "status":"ok" | | Check interval | 1 minute | | Timeout | 10 seconds | | Alert after | 2 consecutive failures |


Step 2: Monitor Kubernetes RuntimeClass Configuration

Validate that the Wasm RuntimeClass object is correctly configured in the cluster. Deploy a lightweight checker as a CronJob:

# runwasi-runtimeclass-probe.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: runwasi-runtimeclass-probe
  namespace: monitoring
spec:
  schedule: "*/5 * * * *"
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          serviceAccountName: runwasi-probe-sa
          containers:
            - name: probe
              image: bitnami/kubectl:latest
              env:
                - name: HEARTBEAT_URL
                  valueFrom:
                    secretKeyRef:
                      name: vigilmon-secrets
                      key: runwasi-runtimeclass-heartbeat-url
              command:
                - /bin/sh
                - -c
                - |
                  set -e
                  # Verify RuntimeClass exists and has correct handler
                  HANDLER=$(kubectl get runtimeclass wasmtime \
                    -o jsonpath='{.handler}' 2>/dev/null)

                  if [ "$HANDLER" = "wasmtime" ]; then
                    echo "RuntimeClass wasmtime handler verified: $HANDLER"
                    wget -qO- "$HEARTBEAT_URL"
                  else
                    echo "ERROR: RuntimeClass handler mismatch or not found: '$HANDLER'" >&2
                    exit 1
                  fi
# RBAC for the probe service account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: runwasi-probe-sa
  namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: runtimeclass-reader
rules:
  - apiGroups: ["node.k8s.io"]
    resources: ["runtimeclasses"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: runwasi-probe-runtimeclass-reader
subjects:
  - kind: ServiceAccount
    name: runwasi-probe-sa
    namespace: monitoring
roleRef:
  kind: ClusterRole
  name: runtimeclass-reader
  apiGroup: rbac.authorization.k8s.io

Create the heartbeat monitor in Vigilmon:

  1. Add Monitor → Heartbeat
  2. Name: runwasi RuntimeClass config
  3. Expected interval: 5 minutes
  4. Grace period: 3 minutes

Step 3: Heartbeat Monitor for Wasm Pod Lifecycle

The definitive runwasi health check is scheduling a real Wasm pod and verifying it completes successfully:

# runwasi-lifecycle-probe.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: runwasi-lifecycle-probe
  namespace: monitoring
spec:
  schedule: "*/10 * * * *"
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          initContainers:
            - name: wasm-probe
              image: ghcr.io/containerd/runwasi-demo:latest
              # This is a minimal WASI module that prints a line and exits 0
              runtimeClassName: wasmtime
          containers:
            - name: reporter
              image: curlimages/curl:latest
              env:
                - name: HEARTBEAT_URL
                  valueFrom:
                    secretKeyRef:
                      name: vigilmon-secrets
                      key: runwasi-lifecycle-heartbeat-url
              command:
                - /bin/sh
                - -c
                - |
                  # If we reach this container, the Wasm initContainer succeeded
                  curl -fsS --max-time 10 "$HEARTBEAT_URL" -o /dev/null
                  echo "Wasm lifecycle heartbeat sent"

Store secrets:

kubectl create secret generic vigilmon-secrets \
  --from-literal=runwasi-runtimeclass-heartbeat-url='https://vigilmon.online/heartbeat/YOUR_RC_TOKEN' \
  --from-literal=runwasi-lifecycle-heartbeat-url='https://vigilmon.online/heartbeat/YOUR_LIFECYCLE_TOKEN' \
  -n monitoring

Create the heartbeat monitor in Vigilmon:

  1. Add Monitor → Heartbeat
  2. Name: runwasi Wasm pod lifecycle
  3. Expected interval: 10 minutes
  4. Grace period: 5 minutes

Step 4: Configure Alert Channels

Route runwasi alerts to your platform engineering team:

  1. In Vigilmon: Alert Channels → Add Channel → Slack Webhook
  2. Add your #platform-engineering webhook URL
  3. Assign to all runwasi monitors

For Wasm pod lifecycle failures (signals end-to-end breakage for all Wasm workloads):

  1. Alert Channels → Add Channel → PagerDuty
  2. Route the runwasi Wasm pod lifecycle heartbeat to on-call
  3. This failure means no Wasm workload on the cluster can run

What You're Now Monitoring

| Component | Monitor Type | What It Detects | |---|---|---| | Shim binary registration | HTTP GET | Shim missing, containerd not recognizing wasmtime | | RuntimeClass configuration | Heartbeat (5 min) | Handler mismatch, RuntimeClass deleted or misconfigured | | Wasm pod lifecycle | Heartbeat (10 min) | Wasm pods can't schedule, WASI execution failures |


Conclusion

runwasi's role as the bridge between Kubernetes pod scheduling and WebAssembly execution means its failures propagate into scheduling failures, not application errors. Most platform observability stacks watch applications, not runtimes — runwasi breaks silently at the shim layer, below the level of pod metrics and log aggregation. External monitoring with Vigilmon closes that gap by validating the shim registration from outside the cluster and running an end-to-end Wasm pod lifecycle probe that confirms the full path from Kubernetes scheduler to WASI execution is working.

Get started free at vigilmon.online. The shim health endpoint and lifecycle heartbeat together give you the two most critical runwasi signals in under ten minutes: is the shim registered with containerd, and can a Wasm pod actually run?

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →