KubeStell (KubeStelllar) is a multi-cluster workload orchestration system that lets you deploy and manage applications across many Kubernetes clusters from a single control plane. It uses BindingPolicy resources to declare where workloads should run across your fleet, propagating configuration to spoke clusters and synchronizing status back to the hub. When the KubeStell control plane fails or a spoke cluster loses connectivity, workloads that appear deployed may stop running on one or more clusters — and there is no built-in cross-cluster health alerting.
In this tutorial you'll set up comprehensive uptime monitoring for your KubeStell multi-cluster environment using Vigilmon — free tier, no credit card required.
Why KubeStell deployments need external monitoring
KubeStell orchestrates across cluster boundaries, which creates failure modes that neither the hub nor the spoke can fully detect on its own:
- KubeStell control plane (kubestellar-controller-manager) crashes — BindingPolicy reconciliation halts; existing workloads continue running on spokes but no updates, new deployments, or removals are propagated
- Space provider disruption — if the underlying OCM (Open Cluster Management) hub cluster or its API is degraded, KubeStell cannot communicate with spoke clusters; the hub looks healthy but all cross-cluster operations silently fail
- Spoke cluster unreachable — if a spoke cluster loses connectivity to the hub, KubeStell stops propagating to it; workloads on the spoke keep running on their last state but diverge from Git and receive no updates
- BindingPolicy selector drift — if cluster labels change or spoke clusters are de-registered, BindingPolicies may match zero clusters; workloads appear configured on the hub but run nowhere
- Sync object status lag — status sync from spokes to hub may fall behind under load; the hub shows stale workload health that masks real failures on spoke clusters
These failures compound across clusters: a single control plane issue can silently stop all workload propagation across dozens of clusters simultaneously.
What you'll need
- A KubeStell hub cluster with at least one spoke cluster registered
- Workloads running on spoke clusters exposed via Service or Ingress
- A free Vigilmon account (sign up takes 30 seconds)
Step 1: Expose health endpoints for monitoring
Verify the KubeStell control plane and spoke cluster connectivity:
# Check KubeStell control plane on the hub
kubectl get pods -n kubestellar -l app=kubestellar-controller-manager
# NAME READY STATUS RESTARTS AGE
# kubestellar-controller-manager-7f8d9c6b5-xk2mn 1/1 Running 0 3d
# Check registered spoke clusters (ManagedClusters via OCM)
kubectl get managedcluster
# NAME HUB ACCEPTED MANAGED CLUSTER URLS JOINED AVAILABLE AGE
# cluster-eu true https://eu-cluster:6443 True True 3d
# cluster-us true https://us-cluster:6443 True True 3d
# cluster-ap true https://ap-cluster:6443 True True 2d
# Check BindingPolicies
kubectl get bindingpolicy -A
# NAMESPACE NAME SYNCED READY AGE
# default web-app-policy True True 2d
Deploy a health check workload that KubeStell propagates to your spoke clusters:
# kubestellar-health.yaml — deploy this to the KubeStell hub; BindingPolicy distributes it
apiVersion: apps/v1
kind: Deployment
metadata:
name: ks-health
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: ks-health
template:
metadata:
labels:
app: ks-health
spec:
containers:
- name: health
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d
readinessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 10
periodSeconds: 30
volumes:
- name: config
configMap:
name: ks-health-nginx
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ks-health-nginx
namespace: default
data:
default.conf: |
server {
listen 80;
location /health {
return 200 '{"status":"ok","orchestrator":"kubestellar"}';
add_header Content-Type application/json;
}
}
---
apiVersion: v1
kind: Service
metadata:
name: ks-health
namespace: default
spec:
type: LoadBalancer
selector:
app: ks-health
ports:
- port: 80
targetPort: 80
protocol: TCP
---
# BindingPolicy to propagate to all spoke clusters
apiVersion: control.kubestellar.io/v1alpha1
kind: BindingPolicy
metadata:
name: ks-health-policy
namespace: default
spec:
clusterSelectors:
- matchLabels:
fleet: production
downsync:
- apiGroup: apps
resource: deployments
namespaces: [default]
labelSelectors:
- matchLabels:
app: ks-health
- apiGroup: ""
resource: services
namespaces: [default]
labelSelectors:
- matchLabels:
app: ks-health
- apiGroup: ""
resource: configmaps
namespaces: [default]
labelSelectors:
- matchLabels:
app: ks-health
kubectl apply -f kubestellar-health.yaml
# Verify propagation to spoke clusters
# (use kubeconfig for each spoke cluster)
kubectl --kubeconfig=cluster-eu.kubeconfig get pods -n default -l app=ks-health
kubectl --kubeconfig=cluster-us.kubeconfig get pods -n default -l app=ks-health
# Get LoadBalancer IPs from each spoke
kubectl --kubeconfig=cluster-eu.kubeconfig get svc ks-health
# NAME TYPE EXTERNAL-IP PORT(S)
# ks-health LoadBalancer 203.0.113.110 80/TCP
kubectl --kubeconfig=cluster-us.kubeconfig get svc ks-health
# NAME TYPE EXTERNAL-IP PORT(S)
# ks-health LoadBalancer 203.0.113.120 80/TCP
# Verify each spoke endpoint
curl http://203.0.113.110/health
# {"status":"ok","orchestrator":"kubestellar"}
curl http://203.0.113.120/health
# {"status":"ok","orchestrator":"kubestellar"}
Step 2: Set up HTTP monitoring in Vigilmon
Add monitors for each spoke cluster's health endpoint:
- Log in to vigilmon.online and go to Monitors → New Monitor
- Choose HTTP / HTTPS as the type
- Set the URL to the EU spoke endpoint:
http://203.0.113.110/health - Set the check interval to 1 minute
- Under Expected response, set:
- Status code:
200 - Response body contains:
"status":"ok"
- Status code:
- Save the monitor
- Repeat for the US spoke:
http://203.0.113.120/health
Repeat for every spoke cluster in your fleet.
Each per-spoke monitor validates the complete KubeStell propagation path: the hub control plane must be healthy, the BindingPolicy must be matching the cluster, OCM connectivity must be working, the workload must be running on the spoke, and the LoadBalancer must be routing traffic.
Why per-spoke external monitoring is essential
KubeStell's hub cluster can report all BindingPolicies as Synced and Ready even when a spoke cluster has lost network connectivity and is running a stale workload. The hub shows what it last successfully propagated, not the current state of the spoke. Vigilmon probes each spoke independently from outside the cluster fleet, giving you ground truth for every region. Its multi-region consensus model eliminates false positives from transient network issues while catching real per-cluster outages within minutes.
Step 3: Monitor TCP ports and the KubeStell control plane
Per-spoke TCP checks:
- Go to Monitors → New Monitor
- Choose TCP Port
- Enter: Host
203.0.113.110, Port80(EU cluster) - Save; repeat for
203.0.113.120:80(US cluster)
KubeStell control plane health:
# Port-forward to KubeStell controller metrics
kubectl port-forward -n kubestellar deploy/kubestellar-controller-manager 8080:8080
# Check health
curl http://localhost:8080/healthz
# ok
# Check readiness
curl http://localhost:8080/readyz
# ok
Expose via Ingress for direct Vigilmon probing:
# ks-controller-ingress.yaml
apiVersion: v1
kind: Service
metadata:
name: ks-controller-health
namespace: kubestellar
spec:
selector:
app: kubestellar-controller-manager
ports:
- port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ks-controller-health
namespace: kubestellar
spec:
rules:
- host: ks-health.your-hub.com
http:
paths:
- path: /healthz
pathType: Exact
backend:
service:
name: ks-controller-health
port:
number: 8080
Add an HTTP monitor in Vigilmon for https://ks-health.your-hub.com/healthz.
Spoke connectivity heartbeat:
# ks-spoke-heartbeat-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: ks-spoke-heartbeat
namespace: default
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
containers:
- name: heartbeat
image: bitnami/kubectl:latest
command:
- sh
- -c
- |
# Check all spoke clusters are available
NOT_READY=$(kubectl get managedcluster -o json | \
jq -r '.items[] | select(.status.conditions[] | select(.type=="ManagedClusterConditionAvailable" and .status!="True")) | .metadata.name')
if [ -n "$NOT_READY" ]; then
echo "Spoke clusters not available: $NOT_READY"
exit 1
fi
curl -fsS https://uptime.vigilmon.online/api/v1/heartbeat/YOUR_HEARTBEAT_KEY
Step 4: Configure alert channels
A KubeStell control plane failure affects all clusters simultaneously. A single spoke failure affects all users in that region. Both require immediate response.
Email alerts
- In Vigilmon, go to Alert Channels → Add Channel → Email
- Enter your platform team's on-call email
- Assign the channel to all KubeStell monitors
Webhook alerts (Slack, PagerDuty, etc.)
- Go to Alert Channels → Add Channel → Webhook
- Enter your webhook URL
- Assign the channel to your monitors
Example payload when a spoke health endpoint goes down:
{
"monitor_name": "KubeStell EU Cluster Health",
"status": "down",
"url": "http://203.0.113.110/health",
"started_at": "2024-01-15T16:20:00Z",
"duration_seconds": 90
}
Run these diagnostics when an alert fires:
# Check KubeStell hub control plane
kubectl get pods -n kubestellar
kubectl logs -n kubestellar -l app=kubestellar-controller-manager --tail=100
# Check all spoke availability
kubectl get managedcluster
kubectl describe managedcluster cluster-eu
# Check BindingPolicy status
kubectl get bindingpolicy -A
kubectl describe bindingpolicy ks-health-policy -n default
# Check propagation status
kubectl get manifestwork -A | grep ks-health
# Check spoke cluster using its own kubeconfig
kubectl --kubeconfig=cluster-eu.kubeconfig get pods -n default
kubectl --kubeconfig=cluster-eu.kubeconfig get nodes
# Check OCM connectivity
kubectl get managedclusteraddons -A
kubectl get addondeploymentconfigs -A
Step 5: Create a public status page
KubeStell typically manages production workloads across multiple regions. Give your teams and users per-region visibility.
- In Vigilmon, go to Status Pages → New Status Page
- Give it a name: "Multi-Cluster Fleet Status"
- Add your monitors: per-spoke HTTP monitors, TCP checks, Control Plane Health, Spoke Connectivity Heartbeat
- Group them by region: EU Cluster, US Cluster, AP Cluster, Control Plane
- Publish the page
Share this URL with your engineering teams and any users who need regional availability visibility.
Putting it all together
Here's a summary of the monitors to create for a KubeStell multi-cluster deployment:
| Monitor | Type | What it catches |
|---------|------|-----------------|
| http://203.0.113.110/health (EU) | HTTP | Full propagation path to EU spoke |
| http://203.0.113.120/health (US) | HTTP | Full propagation path to US spoke |
| 203.0.113.110:80 (EU) | TCP | EU spoke service reachability |
| 203.0.113.120:80 (US) | TCP | US spoke service reachability |
| https://ks-health.your-hub.com/healthz | HTTP | KubeStell hub control plane |
| Spoke connectivity heartbeat | Heartbeat | All ManagedClusters remain Available |
And the KubeStell diagnostics to run when an alert fires:
# Quick triage: hub or spoke?
kubectl get pods -n kubestellar # hub control plane
kubectl get managedcluster # spoke availability
# Which spoke is affected?
kubectl get managedcluster -o custom-columns=NAME:.metadata.name,AVAILABLE:.status.conditions[?(@.type==\"ManagedClusterConditionAvailable\")].status
# Is the workload propagated?
kubectl get manifestwork -A | grep ks-health
kubectl describe manifestwork -n cluster-eu ks-health
# Check BindingPolicy matching
kubectl get bindingpolicy ks-health-policy -n default -o yaml | grep -A10 clusterSelectors
# Force a re-sync
kubectl annotate bindingpolicy ks-health-policy reconcile.kubestellar.io/requestedAt="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Check events on the hub for propagation errors
kubectl get events -n kubestellar | grep -i "error\|fail\|warn"
What's next
- SSL certificate monitoring — add SSL monitors for HTTPS endpoints on each spoke cluster
- Heartbeat monitoring — use Vigilmon heartbeats to verify that workload propagation to each spoke runs on schedule
- Per-region status pages — create a Vigilmon status page group per spoke cluster so regional failures are immediately identifiable without noisy cross-cluster dashboards
Get started free at vigilmon.online — no credit card, monitors start running in under a minute.