tutorial

Monitoring Spin Operator with Vigilmon: Keeping Fermyon WebAssembly Workloads Healthy on Kubernetes

How to monitor Spin Operator with Vigilmon — tracking operator availability, SpinApp CRD reconciliation health, Wasm workload lifecycle probes, and webhook certificate validity from outside your Kubernetes cluster.

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 SpinApp reconciliation 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)
  • kubectl configured 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:

  1. Go to Add Monitor → HTTP
  2. 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:

  1. Add Monitor → Heartbeat
  2. Name: SpinApp reconciliation
  3. Expected interval: 10 minutes
  4. 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:

  1. Add Monitor → SSL Certificate
  2. URL: https://spin-webhook-monitor.your-cluster.internal
  3. Alert when: certificate expires in less than 14 days
  4. Name: Spin Operator webhook TLS

Step 5: Configure Alert Channels

Route Spin Operator alerts to your platform team:

  1. In Vigilmon: Alert Channels → Add Channel → Slack Webhook
  2. Add your #kubernetes-platform or #wasm-ops webhook URL
  3. Assign to all Spin Operator monitors

For webhook certificate expiry (breaks all SpinApp admission when expired):

  1. Alert Channels → Add Channel → Email
  2. Route the Spin Operator webhook TLS SSL monitor to your platform lead email
  3. 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.

Monitor your app with Vigilmon

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

Start free →