k3s: Pod-Monitoring in Grafana (Task 6.5)
ci / test (push) Failing after 23s

kube-state-metrics (NodePort 30808) und ServiceAccount prometheus-infra (nur
nodes/metrics) im Cluster; Prometheus auf infra liest kubelet/cAdvisor per TLS
gegen die k3s-CA. Ziele per file_sd aus kubectl get nodes, cAdvisor auf die
nötigen Reihen begrenzt. Dashboard "k3s – Pods" (Vorgabe nex), Alerts K3s*
nur mit notify. Playbook monitoring-k3s.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Rapp
2026-10-19 16:31:03 +02:00
co-authored by Claude Opus 5.5
parent abf4a75063
commit 4ac251715e
17 changed files with 1271 additions and 13 deletions
@@ -382,15 +382,17 @@ Ersetzt PLAN §8 „1 Data Plane“.
- `test_worker_registry_slot_falls_back_to_tier0_when_list_empty`
- `test_worker_registry_slot_falls_back_when_list_unreachable`
- Prüfung: `make test` PASS. Live tagsüber geht eine tier1-Anfrage an tier0, nachts an GODE-PC-05.
- [ ] **6.5 Pod-Monitoring (k3s in Grafana)** · **Planner:** „Proxmox: Grafana-Dashboard für den Cluster“ · **Files:** Create `deploy/k8s/kube-state-metrics/`, `platform/proxmox/ansible/playbooks/kube-state-metrics-k3s.yml`, `deploy/grafana/dashboards/k3s-pods.json`; Modify `deploy/prometheus/prometheus.yml`, `platform/proxmox/scripts/monitoring-targets.py`, Rolle `infra-stack` (Token), `core/tests/test_artifacts.py`, BETRIEB §7/§14
- [ ] **6.5 Pod-Monitoring (k3s in Grafana)** · **Planner:** „Proxmox: Grafana-Dashboard für den Cluster“ · **Files:** Create `deploy/k8s/monitoring/`, `platform/proxmox/ansible/playbooks/monitoring-k3s.yml`, `deploy/grafana/dashboards/k3s-pods.json`; Modify `deploy/prometheus/prometheus.yml`, `deploy/prometheus/alerts.yml`, `config/healer-rules.yaml`, `platform/proxmox/scripts/monitoring-targets.py`, Rolle `infra-stack` (Token, Ziele), `deploy/compose/infra/docker-compose.yml`, `core/tests/test_artifacts.py`, BETRIEB §7/§14
Ausgangslage 19.10.: Grafana 12.4 und Prometheus laufen auf infra mit Dashboards für Proxmox, Knoten, GPU und knaster; für k3s gibt es kein Ziel. Zustand und Speicher der Pods zeigt bisher nur nex-admin über die Metrics-API (metrics-server, nur Momentwerte, keine Grafana-Datenquelle).
- [ ] kube-state-metrics als Deployment im Namespace `kube-system` (Image gepinnt), Service als NodePort. Liefert Zustand: Bereitschaft, Neustarts, Requests/Limits, Deployments.
- [ ] ServiceAccount `prometheus-infra` mit ClusterRole nur zum Lesen (`nodes`, `nodes/metrics`, `nodes/proxy`), langlebiges Token als Secret. Das Token liegt wie beim pve-exporter nur im LXC unter `/opt/knaster/infra/secrets/k3s-prometheus.token`, kopiert von der Rolle `infra-stack`; die k3s-CA dazu (`/var/lib/rancher/k3s/server/tls/server-ca.crt`), damit kein `insecure_skip_verify` nötig ist. Kubelet-Zertifikate der Agents gegen diese CA prüfen, sonst bewusst entscheiden.
- [ ] Ziele per file_sd statt fester Adressen, weil die k3s-VM (.124) und gpu-pve44/46/48 noch keine Reservierung haben: `monitoring-targets.py` schreibt zusätzlich `kubelet.json` (alle fünf k3s-Knoten, Port 10250, Pfade `/metrics/cadvisor` und `/metrics`) und `kube-state-metrics.json` (NodePort auf jedem Knoten, Prometheus nimmt den ersten erreichbaren bzw. dedupliziert per `instance`).
- [ ] Prometheus-Jobs `kubelet`, `cadvisor`, `kube-state-metrics` in `deploy/prometheus/prometheus.yml`. infra hat nur 4 GB: für cAdvisor `metric_relabel_configs`, die nur `container_cpu_usage_seconds_total`, `container_memory_working_set_bytes`, `container_memory_rss` und Netzwerk behalten und `container=""`/Pause-Container verwerfen. Danach Speicher von Prometheus eine Woche beobachten.
- [ ] ufw in den GPU-VMs (gpu-pve52 lässt heute nur 8178/8179 von .29 zu): 10250 und den NodePort nur von `.188` freigeben (Rolle `k3s-agent` bzw. `gpu-exporters`).
- [ ] Dashboard „k3s – Pods“ (Grundlage Community-Dashboard, z. B. grafana.com 15661/15760, angepasst auf die vorhandenen Metriken) mit Namespace-Auswahl, Vorgabe `nex`: Pods je Knoten, Neustarts, CPU/Speicher gegen Requests/Limits. In die Kiosk-Playlist (5.3) aufnehmen.
- [ ] Alerts in `deploy/prometheus/alerts.yml`: Pod in CrashLoopBackOff > 10 min, Deployment nicht verfügbar, Speicher > 90 % des Limits. Nur melden, kein Healer-Eingriff (der heilt nur VMs).
- [x] (19.10.) kube-state-metrics v2.19.1 im Namespace `kube-system` (`deploy/k8s/monitoring/kube-state-metrics.yaml`, nur die nötigen Ressourcen), Service NodePort 30808.
- [x] (19.10.) ServiceAccount `prometheus-infra`, ClusterRole nur `get nodes/metrics`, langlebiges Token-Secret. Token und CA legt `playbooks/monitoring-k3s.yml` auf ops ab (`/root/.config/knaster/k3s-prometheus.token`, `k3s-ca.crt`), die Rolle `infra-stack` kopiert sie nach `/opt/knaster/infra/secrets/k3s/` (nur dieser Ordner in Prometheus eingehängt). Die kubelet-Zertifikate sind von `k3s-server-ca` signiert und tragen die Knoten-IP (geprüft auf gpu-pve52), daher TLS ohne `insecure_skip_verify`.
- [x] (19.10.) Ziele per file_sd aus `kubectl get nodes` (statt tofu, so ist die k3s-VM dabei): `monitoring-targets.py --k3s-nodes` schreibt `kubelet.json` (alle Knoten, 10250) und `kube-state-metrics.json` (ein Ziel, NodePort auf der Dienst-VM k3s, sonst erster bereiter Knoten; `instance` fest, damit ein Wechsel keine neuen Reihen erzeugt).
- [x] (19.10.) Prometheus-Jobs `kubelet`, `cadvisor`, `kube-state-metrics`. cAdvisor behält nur CPU, Arbeitssatz, RSS, OOM und Netz und verwirft Reihen ohne Pod sowie Pod-Summen/Pause-Container.
- [ ] Speicher von Prometheus eine Woche beobachten (infra hat 4 GB).
- [x] ufw: Die Rolle `k3s-agent` erlaubt 10250 und 30000–32767 schon seit 15.10. aus dem LAN, keine Änderung nötig.
- [x] (19.10.) Dashboard „k3s – Pods“ (`deploy/grafana/dashboards/k3s-pods.json`, eigenes statt Community, passend zu den behaltenen Metriken): Namespace-Auswahl mit Vorgabe `nex`, Kennzahlen, Speicher/CPU je Pod, Tabelle mit Knoten, Neustarts, Speicher gegen Request/Limit, Pods und Speicher je Knoten, PVC-Belegung.
- [ ] Dashboard in die Kiosk-Playlist (5.3) aufnehmen, sobald es die Playlist gibt.
- [x] (19.10.) Alerts `K3sNodeNotReady`, `K3sPodCrashLooping` (> 10 min), `K3sDeploymentUnavailable` (> 15 min), `K3sContainerMemoryNearLimit` (> 90 %, 10 min); Healer-Regeln nur `notify`.
- Prüfung: `make test` PASS (Struktur von prometheus.yml/alerts.yml). Auf infra zeigt `api/v1/targets` die Jobs `kubelet`, `cadvisor`, `kube-state-metrics` mit allen fünf Knoten `up`. Grafana zeigt für `nex` dieselben Pods und ungefähr denselben Speicher wie `kubectl top pods -n nex`. Ein absichtlich kaputtes Test-Deployment löst den CrashLoop-Alert aus.
---