OpenYurt extends Kubernetes to edge computing scenarios — running workloads on edge nodes that may have intermittent connectivity to the cloud control plane. This architecture introduces failure modes that standard Kubernetes monitoring simply can't catch: edge nodes going autonomous, cloud-edge tunnels degrading silently, and node pool health diverging from what kubectl reports.
In this tutorial you'll set up comprehensive uptime monitoring for your OpenYurt deployment using Vigilmon — free tier, no credit card required.
Why OpenYurt deployments need external monitoring
OpenYurt's edge autonomy model means your cluster can look healthy to the central control plane while edge nodes are serving stale data, have lost tunnel connectivity, or have fallen back to autonomous operation without anyone noticing.
Key failure modes that internal probes miss:
- Cloud-edge tunnel degradation — the
ravenoryurt-tunnel-servercomponent loses connectivity; edge pods stay Running, but traffic from the cloud can no longer reach them - Edge node autonomy triggered silently —
YurtHubenables autonomous mode when the API server is unreachable; workloads keep running but management plane visibility is severed - NodePool divergence — an entire pool of edge nodes falls behind on scheduling without the central dashboard flagging it
- YurtAppDaemon/YurtAppSet rollout failures — edge-specific DaemonSet equivalents stall on unreachable nodes, causing partial rollouts that appear complete from the control plane
- Raven gateway unavailability — east-west traffic between edge node pools fails when the L3 gateway goes down, even though pods on individual nodes report healthy
- DNS resolution at the edge — edge-local DNS servers diverge from the cloud; services resolve to stale endpoints
External monitoring from multiple geographic regions is the only reliable way to observe what the edge is actually serving to end users.
What you'll need
- An OpenYurt cluster with at least one edge node pool
- Edge nodes or services exposed via a public or VPN-accessible endpoint
- A free Vigilmon account (sign up takes 30 seconds)
Step 1: Add a health endpoint to your edge workloads
OpenYurt workloads are regular Kubernetes pods. Before monitoring, ensure your application exposes a /health endpoint and is deployed as a YurtAppSet or standard Deployment with proper tolerations.
# edge-app-deployment.yaml
apiVersion: apps.openyurt.io/v1alpha1
kind: YurtAppSet
metadata:
name: edge-api
namespace: production
spec:
selector:
matchLabels:
app: edge-api
workloadTemplate:
deploymentTemplate:
metadata:
labels:
app: edge-api
spec:
replicas: 2
template:
metadata:
labels:
app: edge-api
spec:
tolerations:
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
tolerationSeconds: 300
containers:
- name: edge-api
image: your-registry/edge-api:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
topology:
pools:
- name: edge-pool-us-west
nodeSelectorTerm:
matchExpressions:
- key: apps.openyurt.io/nodepool
operator: In
values:
- edge-pool-us-west
replicas: 2
A minimal health handler in Node.js:
// health.js
app.get('/health', (req, res) => {
res.json({
status: 'ok',
node: process.env.NODE_NAME || 'unknown',
pool: process.env.NODE_POOL || 'unknown',
timestamp: new Date().toISOString(),
});
});
Step 2: Expose your edge services externally
Edge nodes often sit behind NAT or private networks. Use one of these patterns to expose them for external monitoring:
Option A: LoadBalancer Service (cloud edge)
apiVersion: v1
kind: Service
metadata:
name: edge-api-svc
namespace: production
spec:
type: LoadBalancer
selector:
app: edge-api
ports:
- protocol: TCP
port: 80
targetPort: 8080
Option B: NodePort with firewall rule (bare-metal edge)
apiVersion: v1
kind: Service
metadata:
name: edge-api-svc
namespace: production
spec:
type: NodePort
selector:
app: edge-api
ports:
- protocol: TCP
port: 8080
nodePort: 30080
Then open port 30080 on your edge node's firewall:
# On the edge node
sudo ufw allow 30080/tcp
Step 3: Monitor the cloud-edge tunnel endpoint
The yurt-tunnel-server is the backbone of OpenYurt's cloud-to-edge communication. Monitor it directly.
Find the tunnel server's external address:
kubectl get svc -n kube-system | grep yurt-tunnel-server
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# yurt-tunnel-server LoadBalancer 10.96.100.50 203.0.113.10 10250:31250/TCP,10255:31255/TCP
The tunnel server exposes a metrics endpoint:
curl http://<tunnel-server-ip>:10251/metrics | grep yurt_tunnel
Create a lightweight proxy to expose tunnel health as an HTTP endpoint your monitoring can poll:
// tunnel-health-proxy/main.go
package main
import (
"encoding/json"
"fmt"
"net/http"
"os/exec"
)
type TunnelStatus struct {
Status string `json:"status"`
ConnectedNodes int `json:"connected_nodes"`
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
// Check that yurt-tunnel-agent pods are running
cmd := exec.Command("kubectl", "get", "pods", "-n", "kube-system",
"-l", "k8s-app=yurt-tunnel-agent", "--field-selector=status.phase=Running",
"-o", "jsonpath={.items[*].status.phase}")
out, err := cmd.Output()
if err != nil {
http.Error(w, "tunnel check failed", http.StatusServiceUnavailable)
return
}
status := TunnelStatus{
Status: "ok",
ConnectedNodes: len(string(out)),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(status)
}
func main() {
http.HandleFunc("/health", healthHandler)
fmt.Println("Tunnel health proxy listening on :9090")
http.ListenAndServe(":9090", nil)
}
Step 4: Add a Vigilmon HTTP monitor for the edge service
Log in to Vigilmon and navigate to Monitors → Add Monitor.
| Field | Value |
|-------|-------|
| Monitor type | HTTP |
| Name | OpenYurt edge-api (us-west pool) |
| URL | http://<edge-node-ip>:30080/health (or your LoadBalancer IP) |
| Check interval | 1 minute |
| HTTP method | GET |
| Expected status | 200 |
| Response must contain | "status":"ok" |
| Regions | Select 3+ regions geographically close to your edge site |
Click Save Monitor. Vigilmon will start checking from all selected regions immediately.
Step 5: Add a TCP monitor for the Raven gateway
Raven is OpenYurt's L3 connectivity component for inter-pool communication. Monitor the gateway's exposed port to detect when east-west traffic would fail:
# Find the raven-gateway external IP
kubectl get svc -n kube-system raven-gateway
In Vigilmon, add a second monitor:
| Field | Value |
|-------|-------|
| Monitor type | TCP |
| Name | OpenYurt Raven Gateway (L3) |
| Host | <raven-gateway-external-ip> |
| Port | 4500 (default IPSec/Raven port) |
| Check interval | 1 minute |
Step 6: Monitor node pool health via a status API
Create a simple node pool status exporter to track per-pool readiness:
# nodepool-status-api/app.py
from flask import Flask, jsonify
import subprocess
import json
app = Flask(__name__)
@app.route('/health/nodepool/<pool_name>')
def nodepool_health(pool_name):
result = subprocess.run(
['kubectl', 'get', 'nodepools', pool_name, '-o', 'json'],
capture_output=True, text=True
)
if result.returncode != 0:
return jsonify({'status': 'error', 'pool': pool_name}), 503
data = json.loads(result.stdout)
conditions = data.get('status', {}).get('conditions', [])
ready = any(c['type'] == 'PoolInitialized' and c['status'] == 'True'
for c in conditions)
if not ready:
return jsonify({'status': 'degraded', 'pool': pool_name}), 503
ready_nodes = data.get('status', {}).get('readyNodeNum', 0)
total_nodes = data.get('status', {}).get('nodeNum', 0)
return jsonify({
'status': 'ok',
'pool': pool_name,
'ready_nodes': ready_nodes,
'total_nodes': total_nodes,
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8090)
Add a Vigilmon HTTP monitor for each node pool:
| Field | Value |
|-------|-------|
| Monitor type | HTTP |
| Name | NodePool: edge-pool-us-west |
| URL | http://<control-plane-ip>:8090/health/nodepool/edge-pool-us-west |
| Expected status | 200 |
| Response must contain | "status":"ok" |
Step 7: Configure alerts
In Vigilmon, go to Alerts → Alert Channels and set up your notification channels (email, Slack, PagerDuty, etc.).
Then apply an alert policy to each OpenYurt monitor:
| Setting | Recommended value | |---------|-------------------| | Alert after | 2 consecutive failures (reduces false positives from brief tunnel drops) | | Recovery alert | Enabled (know when edge autonomy resolves) | | Alert channel | Your on-call channel |
For tunnel monitors specifically, a 2-failure threshold before alerting matches OpenYurt's built-in reconnection retry window.
Step 8: Set up a status page
If you serve external customers from edge nodes, create a public status page in Vigilmon:
- Navigate to Status Pages → Create Status Page
- Add your edge-api monitors grouped by pool name
- Add the Raven gateway monitor as "Internal Infrastructure"
- Share the status page URL with your operations team
What you're monitoring now
| Monitor | What it detects | |---------|-----------------| | Edge HTTP (per pool) | Application-level failures at the edge, pod crashes, 5xx errors | | Raven Gateway TCP | L3 inter-pool connectivity loss | | Node pool status API | Pool-wide readiness degradation, partial node failures | | Tunnel health proxy | Cloud-edge tunnel breaks, autonomous mode triggers |
Conclusion
OpenYurt's edge autonomy model is powerful, but it also makes failures harder to see. Kubernetes control-plane liveness is not the same as edge user experience. Vigilmon gives you an external vantage point that catches tunnel outages, node pool degradation, and routing failures that internal probes miss — no agents to install on edge nodes, just lightweight HTTP and TCP checks from multiple regions.
Sign up for a free Vigilmon account and add your first OpenYurt monitor today.