Spin Operator is a Kubernetes operator from Fermyon that enables you to deploy and manage Spin WebAssembly applications as native Kubernetes workloads using SpinApp custom resource definitions. Platform teams running Spin Operator manage the full lifecycle of Wasm microservices through CRDs — when the operator goes down, no new SpinApp resources are reconciled, existing deployments lose health management, and autoscaling stops working silently. Vigilmon gives you external monitoring that watches the operator control loop and validates that Wasm workloads are being actively managed.
What You'll Build
- Vigilmon HTTP monitors for the Spin Operator health and metrics endpoints
- A heartbeat monitor validating that
SpinAppreconciliation completes on time - A webhook certificate validity monitor to catch TLS expiry before admission breaks
- Alert channels routed to your platform engineering team
Prerequisites
- Spin Operator installed in your Kubernetes cluster (via Helm or kubectl apply)
kubectlconfigured with cluster access- A free account at vigilmon.online
Why Monitoring Spin Operator Matters
Spin Operator runs as a controller in your cluster and manages the gap between SpinApp desired state and actual running Wasm workloads. Its failure modes are subtle:
Operator pod crashes stop all reconciliation. When the spin-operator-controller-manager pod crashes, no new SpinApp resources are processed and no existing SpinApps are updated. Kubernetes schedules no alerts — the control plane is healthy, the cluster is healthy, but your Wasm applications are stuck in whatever state they were in when the operator died.
Webhook TLS certificate expiry breaks all SpinApp admission. Spin Operator registers a validating and mutating admission webhook. The webhook TLS certificate — typically provisioned by cert-manager — has a fixed TTL. When it expires, every kubectl apply for a SpinApp resource is rejected with a TLS handshake error. The cluster and operator pod appear healthy; only the admission path is broken.
CRD schema drift blocks upgrades. When a Spin Operator upgrade introduces a new SpinApp spec version and the old CRD schema is not updated, new SpinApps using the updated spec fail admission silently. Existing SpinApps continue running from last known state, masking the breakage until a restart or scale event is triggered.
OCI registry pull failures for Wasm modules manifest as reconciliation errors in the operator log but not as pod failures. The SpinApp resource shows ErrImagePull equivalents in its status, but no Kubernetes event is emitted at the workload level — the operator is the only observer of this failure and must be monitored directly.
Step 1: Monitor the Spin Operator Health Endpoint
Spin Operator exposes a health endpoint via its controller-runtime base. Expose it via a Kubernetes Service for external monitoring:
# spin-operator-metrics-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: spin-operator-metrics
namespace: spin-operator-system
spec:
selector:
control-plane: controller-manager
app.kubernetes.io/name: spin-operator
ports:
- name: metrics
port: 8080
targetPort: 8080
- name: health
port: 8081
targetPort: 8081
type: ClusterIP
kubectl apply -f spin-operator-metrics-svc.yaml
# Port-forward for testing
kubectl port-forward -n spin-operator-system svc/spin-operator-metrics 8081:8081 &
curl http://localhost:8081/healthz
# Expected: {"status":"ok"}
For external monitoring, expose this via a NodePort or an Ingress:
# spin-operator-metrics-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: spin-operator-health-external
namespace: spin-operator-system
spec:
selector:
control-plane: controller-manager
app.kubernetes.io/name: spin-operator
ports:
- port: 8081
nodePort: 30281
type: NodePort
kubectl apply -f spin-operator-metrics-nodeport.yaml
In the Vigilmon dashboard:
- Go to Add Monitor → HTTP
- Configure:
| Field | Value |
|---|---|
| Name | Spin Operator health |
| URL | http://your-node-ip:30281/healthz |
| Method | GET |
| Expected status | 200 |
| Response body contains | ok |
| Check interval | 1 minute |
| Timeout | 10 seconds |
| Alert after | 2 consecutive failures |
Step 2: Monitor the Metrics Endpoint for Reconciliation Health
The operator's Prometheus metrics endpoint exposes reconciliation queue depth and error rates. A rising queue depth with no drain means the operator is running but unable to process SpinApps:
# Port-forward metrics
kubectl port-forward -n spin-operator-system svc/spin-operator-metrics 8080:8080 &
curl -s http://localhost:8080/metrics | grep controller_runtime
Expose metrics externally at NodePort 30280 using the same Service pattern from Step 1 (add port 8080/30280). Then in Vigilmon:
| Field | Value |
|---|---|
| Name | Spin Operator metrics |
| URL | http://your-node-ip:30280/metrics |
| Method | GET |
| Expected status | 200 |
| Response body contains | controller_runtime_reconcile_total |
| Check interval | 2 minutes |
| Timeout | 15 seconds |
| Alert after | 2 consecutive failures |
Step 3: Heartbeat Monitor for SpinApp Reconciliation
A reconciliation heartbeat proves the operator's control loop is running end-to-end. Deploy a minimal SpinApp and validate its status on a schedule:
# /usr/local/bin/spinapp-reconcile-probe.sh
#!/bin/bash
set -euo pipefail
HEARTBEAT_URL="${SPINAPP_HEARTBEAT_URL}"
NAMESPACE="spin-probes"
SPINAPP_NAME="reconcile-probe"
# Ensure namespace and SpinApp exist
kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
cat <<EOF | kubectl apply -f - >/dev/null
apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
name: $SPINAPP_NAME
namespace: $NAMESPACE
spec:
image: ghcr.io/fermyon/spin-operator/samples/hello-spin:latest
replicas: 1
executor: containerd-shim-spin
EOF
# Wait for SpinApp to reach Ready
for i in $(seq 1 30); do
STATUS=$(kubectl get spinapp "$SPINAPP_NAME" -n "$NAMESPACE" \
-o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "")
if [ "$STATUS" = "True" ]; then
curl -fsS --max-time 10 "$HEARTBEAT_URL" -o /dev/null
echo "$(date): SpinApp reconciliation probe OK"
exit 0
fi
sleep 5
done
echo "$(date): ERROR — SpinApp not Ready after 150s" >&2
exit 1
# /etc/systemd/system/spinapp-probe.service
[Unit]
Description=Spin Operator SpinApp reconciliation probe
[Service]
Type=oneshot
EnvironmentFile=/etc/spinapp-probe.env
ExecStart=/usr/local/bin/spinapp-reconcile-probe.sh
# /etc/systemd/system/spinapp-probe.timer
[Unit]
Description=Run SpinApp reconciliation probe every 10 minutes
[Timer]
OnBootSec=5min
OnUnitActiveSec=10min
Unit=spinapp-probe.service
[Install]
WantedBy=timers.target
# /etc/spinapp-probe.env
SPINAPP_HEARTBEAT_URL=https://vigilmon.online/heartbeat/YOUR_SPINAPP_TOKEN
chmod +x /usr/local/bin/spinapp-reconcile-probe.sh
systemctl daemon-reload
systemctl enable --now spinapp-probe.timer
Create the heartbeat monitor in Vigilmon:
- Add Monitor → Heartbeat
- Name:
SpinApp reconciliation - Expected interval: 10 minutes
- Grace period: 5 minutes
Step 4: Monitor the Admission Webhook Certificate
Spin Operator's admission webhook depends on a valid TLS certificate. Add a Vigilmon SSL monitor to catch expiry before it breaks SpinApp admission:
If you expose the webhook externally through an Ingress (recommended for monitoring purposes):
# spin-operator-webhook-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spin-operator-webhook-monitor
namespace: spin-operator-system
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
rules:
- host: spin-webhook-monitor.your-cluster.internal
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: spin-operator-webhook-service
port:
number: 443
tls:
- hosts:
- spin-webhook-monitor.your-cluster.internal
secretName: spin-operator-webhook-tls
In Vigilmon, add an SSL monitor:
- Add Monitor → SSL Certificate
- URL:
https://spin-webhook-monitor.your-cluster.internal - Alert when: certificate expires in less than 14 days
- Name:
Spin Operator webhook TLS
Step 5: Configure Alert Channels
Route Spin Operator alerts to your platform team:
- In Vigilmon: Alert Channels → Add Channel → Slack Webhook
- Add your
#kubernetes-platformor#wasm-opswebhook URL - Assign to all Spin Operator monitors
For webhook certificate expiry (breaks all SpinApp admission when expired):
- Alert Channels → Add Channel → Email
- Route the
Spin Operator webhook TLSSSL monitor to your platform lead email - Set alert threshold to 14 days before expiry — cert-manager renewal should trigger by day 30 but monitoring at 14 days catches renewal failures early
What You're Now Monitoring
| Component | Monitor Type | What It Detects | |---|---|---| | Spin Operator health | HTTP GET | Operator pod down or health check failing | | Spin Operator metrics | HTTP GET | Metrics endpoint unavailable, reconciler not running | | SpinApp reconciliation | Heartbeat (10 min) | Control loop stalled, CRD admission broken, OCI pull failures | | Webhook TLS certificate | SSL | Certificate expiry before SpinApp admission breaks |
Conclusion
Spin Operator bridges Kubernetes scheduling with the Wasm runtime layer — and its failure modes are invisible to standard cluster monitoring. The operator pod appears healthy while reconciliation stalls, webhook TLS expires silently, and SpinApp status conditions go unobserved. External monitoring with Vigilmon catches each of these failure modes independently: the health endpoint probe detects pod crashes, the reconciliation heartbeat detects control loop stalls, and the SSL monitor catches webhook certificate expiry before it blocks your deployment pipeline.
Get started free at vigilmon.online. The health endpoint probe and reconciliation heartbeat together give you the two most critical Spin Operator signals in under fifteen minutes of setup.