|
| 1 | +# Cluster Nodes dashboard (as-code) — at-a-glance node up/down. Uses |
| 2 | +# `up{job="kubernetes-nodes"}` (the kubelet scrape): it reports 1/0 PER NODE and, |
| 3 | +# unlike node-exporter metrics, the target PERSISTS as 0 when a node is |
| 4 | +# unreachable (nodes come from k8s service discovery), so a down node shows red |
| 5 | +# rather than just disappearing. Auto-loaded by the Grafana sidecar. |
| 6 | +# |
| 7 | +# Note: this reflects kubelet reachability. A node that's up but cordoned still |
| 8 | +# reads UP here (kubelet is fine) — distinguishing Ready/cordoned/pressure needs |
| 9 | +# kube-state-metrics (currently disabled in prometheus-values.yaml). |
| 10 | +apiVersion: v1 |
| 11 | +kind: ConfigMap |
| 12 | +metadata: |
| 13 | + name: grafana-dashboard-cluster |
| 14 | + namespace: monitoring |
| 15 | + labels: |
| 16 | + grafana_dashboard: "1" |
| 17 | + annotations: |
| 18 | + grafana_folder: "Hosts" |
| 19 | +data: |
| 20 | + cluster.json: | |
| 21 | + { |
| 22 | + "uid": "cluster-nodes", |
| 23 | + "title": "Cluster Nodes", |
| 24 | + "tags": ["cluster", "nodes"], |
| 25 | + "timezone": "browser", |
| 26 | + "schemaVersion": 39, |
| 27 | + "refresh": "1m", |
| 28 | + "time": { "from": "now-24h", "to": "now" }, |
| 29 | + "templating": { "list": [] }, |
| 30 | + "annotations": { "list": [] }, |
| 31 | + "panels": [ |
| 32 | + { |
| 33 | + "id": 1, "type": "stat", "title": "Node status (kubelet reachable)", |
| 34 | + "datasource": { "type": "prometheus", "uid": "prometheus" }, |
| 35 | + "gridPos": { "h": 8, "w": 18, "x": 0, "y": 0 }, |
| 36 | + "targets": [ { "refId": "A", "expr": "up{job=\"kubernetes-nodes\"}", "legendFormat": "{{instance}}" } ], |
| 37 | + "fieldConfig": { |
| 38 | + "defaults": { |
| 39 | + "mappings": [ |
| 40 | + { "type": "value", "options": { "0": { "text": "DOWN", "color": "red" }, "1": { "text": "UP", "color": "green" } } } |
| 41 | + ], |
| 42 | + "thresholds": { "mode": "absolute", "steps": [ { "color": "red", "value": null }, { "color": "green", "value": 1 } ] } |
| 43 | + }, |
| 44 | + "overrides": [] |
| 45 | + }, |
| 46 | + "options": { "colorMode": "background", "graphMode": "none", "textMode": "value_and_name", "reduceOptions": { "calcs": ["lastNotNull"] } } |
| 47 | + }, |
| 48 | + { |
| 49 | + "id": 2, "type": "stat", "title": "Nodes up / total", |
| 50 | + "datasource": { "type": "prometheus", "uid": "prometheus" }, |
| 51 | + "gridPos": { "h": 8, "w": 6, "x": 18, "y": 0 }, |
| 52 | + "targets": [ |
| 53 | + { "refId": "A", "expr": "sum(up{job=\"kubernetes-nodes\"})", "legendFormat": "up" }, |
| 54 | + { "refId": "B", "expr": "count(up{job=\"kubernetes-nodes\"})", "legendFormat": "total" } |
| 55 | + ], |
| 56 | + "fieldConfig": { "defaults": { "unit": "short", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null } ] } }, "overrides": [] }, |
| 57 | + "options": { "colorMode": "value", "graphMode": "none", "textMode": "value_and_name", "reduceOptions": { "calcs": ["lastNotNull"] } } |
| 58 | + }, |
| 59 | + { |
| 60 | + "id": 3, "type": "timeseries", "title": "Node up/down history (1 = up, 0 = down)", |
| 61 | + "datasource": { "type": "prometheus", "uid": "prometheus" }, |
| 62 | + "gridPos": { "h": 8, "w": 24, "x": 0, "y": 8 }, |
| 63 | + "targets": [ { "refId": "A", "expr": "up{job=\"kubernetes-nodes\"}", "legendFormat": "{{instance}}" } ], |
| 64 | + "fieldConfig": { "defaults": { "unit": "short", "min": 0, "max": 1, "custom": { "drawStyle": "line", "lineInterpolation": "stepAfter", "fillOpacity": 15 } }, "overrides": [] }, |
| 65 | + "options": { "legend": { "displayMode": "table", "placement": "bottom", "calcs": ["min"] } } |
| 66 | + } |
| 67 | + ] |
| 68 | + } |
0 commit comments