Kraan is a GitOps-native add-on manager for Kubernetes. It organizes your cluster's HelmReleases, Kustomizations, and other Flux-based resources into dependency-aware layers, ensuring that foundational add-ons (like cert-manager or ingress-nginx) are fully ready before dependent add-ons deploy on top of them. When the Kraan controller fails or an AddonsLayer gets stuck, the entire add-on dependency chain freezes — upstream layers block downstream layers, and your cluster drifts from its desired Git state without alerting.
In this tutorial you'll set up comprehensive uptime monitoring for your Kraan-managed Kubernetes cluster using Vigilmon — free tier, no credit card required.
Why Kraan clusters need external monitoring
Kraan adds a dependency graph on top of Flux's GitOps reconciliation. Failures here compound:
- Kraan controller pod crashes — all
AddonsLayerreconciliation halts; running add-ons continue but nothing is updated, rolled back, or newly installed; Git divergence accumulates silently - AddonsLayer stuck in Deploying — if a layer's Helm release or Kustomization fails, the layer never reaches
Deployed; every downstream layer waits indefinitely; there is no timeout or self-healing built in - Source repository unreachable — if Kraan's GitRepository source loses connectivity, all layers stop reconciling; the cluster runs on its last-applied state with no indication that new commits are being ignored
- HelmRelease conflict within a layer — if two resources in the same layer conflict, Kraan may repeatedly reconcile without making progress; the layer oscillates and blocks its dependents
- RBAC misconfiguration — if Kraan's service account loses permissions, reconciliation fails silently; pods run but no changes from Git are applied
These failure modes are particularly hard to detect because add-ons keep running from their last-deployed state — the cluster looks healthy while continuously drifting from what Git declares.
What you'll need
- A Kubernetes cluster with Kraan and Flux installed
- At least one add-on managed by Kraan that exposes a health endpoint
- A free Vigilmon account (sign up takes 30 seconds)
Step 1: Expose a health endpoint for monitoring
Verify that Kraan is running and check the state of your AddonsLayers:
# Check Kraan controller
kubectl get pods -n gotk-system -l app=kraan-controller
# NAME READY STATUS RESTARTS AGE
# kraan-controller-5f7d9c8b4-xp2mn 1/1 Running 0 7d
# Check all AddonsLayers
kubectl get addonslayer -A
# NAMESPACE NAME VERSION STATUS
# default base-layer v1.0.0 Deployed
# default platform-layer v1.0.0 Deployed
# default apps-layer v1.0.0 Deployed
# Check AddonsLayer details
kubectl describe addonslayer apps-layer -n default
Kraan-managed add-ons like ingress-nginx or cert-manager expose their own health endpoints. Use the most critical one as your primary health signal:
# Example: ingress-nginx health check (managed by Kraan's base-layer)
kubectl get svc -n ingress-nginx ingress-nginx-controller
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# ingress-nginx-controller LoadBalancer 10.96.100.50 203.0.113.100 80/TCP,443/TCP
# Test the ingress health endpoint
curl http://203.0.113.100/healthz
# ok
For a dedicated end-to-end probe, deploy a health check app via a Kraan-managed AddonsLayer:
# Add to your apps-layer HelmRelease or Kustomization source:
# health-check-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kraan-health
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: kraan-health
template:
metadata:
labels:
app: kraan-health
spec:
containers:
- name: health
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d
volumes:
- name: config
configMap:
name: kraan-health-nginx
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kraan-health-nginx
namespace: default
data:
default.conf: |
server {
listen 80;
location /health {
return 200 '{"status":"ok","manager":"kraan"}';
add_header Content-Type application/json;
}
}
---
apiVersion: v1
kind: Service
metadata:
name: kraan-health
namespace: default
spec:
type: LoadBalancer
selector:
app: kraan-health
ports:
- port: 80
targetPort: 80
protocol: TCP
Commit this file to your Git repository so Kraan deploys it through its GitOps pipeline. This app becomes your most valuable monitor — it only exists if Kraan's full reconciliation chain worked.
# After Git commit and Kraan reconciliation
kubectl get svc kraan-health
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# kraan-health LoadBalancer 10.96.110.10 203.0.113.105 80/TCP 5m
curl http://203.0.113.105/health
# {"status":"ok","manager":"kraan"}
Step 2: Set up HTTP monitoring in Vigilmon
With your health endpoint available, add it to Vigilmon:
- Log in to vigilmon.online and go to Monitors → New Monitor
- Choose HTTP / HTTPS as the type
- Set the URL to your endpoint:
http://203.0.113.105/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
If this app was deployed via Kraan's GitOps pipeline, monitoring it validates the complete Kraan stack: Git connectivity, Kraan reconciliation, AddonsLayer dependency resolution, Helm/Kustomize execution, and pod scheduling all have to work for a response to arrive.
Why external monitoring catches what Flux and Kraan miss
Flux's Kustomization and HelmRelease objects surface reconciliation errors as conditions on their CRDs — but only if you're watching them. There's no built-in alerting when AddonsLayer gets stuck. Vigilmon probes from outside your cluster and notifies you without requiring any in-cluster tooling to be operational. Its multi-region consensus model eliminates false positives while still detecting real outages within minutes.
Step 3: Monitor TCP ports and the Kraan controller
Add monitors to detect failures at multiple layers:
Service TCP check:
- Go to Monitors → New Monitor
- Choose TCP Port
- Enter: Host
203.0.113.105, Port80 - Save the monitor
Kraan controller metrics endpoint:
# Port-forward to Kraan controller metrics
kubectl port-forward -n gotk-system deploy/kraan-controller 8080:8080
# Check Kraan health
curl http://localhost:8080/healthz
# ok
# Check Kraan readiness
curl http://localhost:8080/readyz
# ok
Expose these via an Ingress if you want Vigilmon to probe them directly:
# kraan-controller-ingress.yaml
apiVersion: v1
kind: Service
metadata:
name: kraan-controller-health
namespace: gotk-system
spec:
selector:
app: kraan-controller
ports:
- name: metrics
port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kraan-health
namespace: gotk-system
spec:
rules:
- host: kraan-health.your-cluster.com
http:
paths:
- path: /healthz
pathType: Exact
backend:
service:
name: kraan-controller-health
port:
number: 8080
Add an HTTP monitor in Vigilmon for https://kraan-health.your-cluster.com/healthz.
GitOps reconciliation heartbeat:
Use a Kubernetes CronJob to verify reconciliation is happening and push a heartbeat to Vigilmon:
# kraan-heartbeat-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: kraan-reconcile-heartbeat
namespace: default
spec:
schedule: "*/10 * * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: default
restartPolicy: Never
containers:
- name: heartbeat
image: bitnami/kubectl:latest
command:
- sh
- -c
- |
STATUS=$(kubectl get addonslayer -A -o jsonpath='{.items[*].status.state}')
if echo "$STATUS" | grep -qv "Deployed"; then
echo "Some AddonsLayers not Deployed: $STATUS"
exit 1
fi
curl -fsS https://uptime.vigilmon.online/api/v1/heartbeat/YOUR_HEARTBEAT_KEY
Step 4: Configure alert channels
An AddonsLayer stuck in Deploying can cascade and freeze your entire add-on stack. Alert the moment reconciliation breaks.
Email alerts
- In Vigilmon, go to Alert Channels → Add Channel → Email
- Enter your platform team's on-call email
- Assign the channel to all Kraan 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 the Kraan health endpoint goes down:
{
"monitor_name": "Kraan Add-on Health",
"status": "down",
"url": "http://203.0.113.105/health",
"started_at": "2024-01-15T11:00:00Z",
"duration_seconds": 240
}
Run these diagnostics when an alert fires:
# Check Kraan controller
kubectl get pods -n gotk-system -l app=kraan-controller
kubectl logs -n gotk-system -l app=kraan-controller --tail=100
# Check all AddonsLayer states
kubectl get addonslayer -A
kubectl describe addonslayer -A | grep -A10 "Status:"
# Find stuck layers
kubectl get addonslayer -A -o json | \
jq '.items[] | select(.status.state != "Deployed") | {name: .metadata.name, state: .status.state}'
# Check HelmReleases managed by Kraan
kubectl get helmrelease -A
kubectl get kustomization -A
# Check Flux GitRepository source
kubectl get gitrepository -A
kubectl describe gitrepository -n flux-system flux-system
# Check RBAC
kubectl auth can-i --list --as=system:serviceaccount:gotk-system:kraan-controller
Step 5: Create a public status page
Kraan manages foundational infrastructure add-ons. A status page gives all engineering teams visibility when the add-on layer is degraded.
- In Vigilmon, go to Status Pages → New Status Page
- Give it a name: "Cluster Add-on Status"
- Add your monitors: Kraan Health HTTP, Service TCP, Controller Health, Reconciliation Heartbeat
- Group them: Add-on Services, Kraan Controller, GitOps Reconciliation
- Publish the page
Share this URL with your platform, application, and DevOps teams.
Putting it all together
Here's a summary of the monitors to create for a Kraan-managed cluster:
| Monitor | Type | What it catches |
|---------|------|-----------------|
| http://203.0.113.105/health | HTTP | Full GitOps chain (Git → Kraan → AddonsLayer → pod → response) |
| 203.0.113.105:80 | TCP | Service reachability |
| https://kraan-health.your-cluster.com/healthz | HTTP | Kraan controller process health |
| AddonsLayer reconciliation heartbeat | Heartbeat | All layers remain in Deployed state |
And the Kraan diagnostics to run when an alert fires:
# Quick triage: controller or layer?
kubectl get pods -n gotk-system | grep kraan
kubectl get addonslayer -A
# Which layer is stuck?
kubectl get addonslayer -A -o custom-columns=NAME:.metadata.name,STATE:.status.state,MSG:.status.reason
# Check the layer's resources
kubectl get helmrelease -A | grep -v "True"
kubectl get kustomization -A | grep -v "True"
# Force a Kraan reconciliation
kubectl annotate addonslayer apps-layer reconcile.fluxcd.io/requestedAt="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Check Git source freshness
kubectl get gitrepository -A -o custom-columns=NAME:.metadata.name,READY:.status.conditions[0].status,MSG:.status.conditions[0].message
What's next
- SSL certificate monitoring — add SSL monitors for HTTPS endpoints of Kraan-managed add-ons like ingress-nginx and cert-manager
- Heartbeat monitoring — use Vigilmon heartbeats to validate that each
AddonsLayerstays inDeployedon schedule - Layer-by-layer coverage — create separate monitors for the critical add-ons in each Kraan layer (base, platform, apps) to pinpoint failures at the right dependency level
Get started free at vigilmon.online — no credit card, monitors start running in under a minute.