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:
- Go to Add Monitor → HTTP
- 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:
- Add Monitor → Heartbeat
- Name:
runwasi RuntimeClass config - Expected interval: 5 minutes
- 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:
- Add Monitor → Heartbeat
- Name:
runwasi Wasm pod lifecycle - Expected interval: 10 minutes
- Grace period: 5 minutes
Step 4: Configure Alert Channels
Route runwasi alerts to your platform engineering team:
- In Vigilmon: Alert Channels → Add Channel → Slack Webhook
- Add your
#platform-engineeringwebhook URL - Assign to all runwasi monitors
For Wasm pod lifecycle failures (signals end-to-end breakage for all Wasm workloads):
- Alert Channels → Add Channel → PagerDuty
- Route the
runwasi Wasm pod lifecycleheartbeat to on-call - 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?