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
@@ -0,0 +1,74 @@
# Pod-Monitoring (Task 6.5): kube-state-metrics und Lesezugang für Prometheus in k3s, danach der Infra-Stack
# (Prometheus-Jobs kubelet/cadvisor/kube-state-metrics, file_sd-Ziele, Dashboard „k3s – Pods“). Läuft auf ops:
# ansible-playbook playbooks/monitoring-k3s.yml
# Token und CA landen auf ops unter /root/.config/knaster (0600), die Rolle infra-stack kopiert sie nach infra.
- name: k3s – kube-state-metrics und Zugang für Prometheus
hosts: localhost
connection: local
gather_facts: false
vars:
manifests: "{{ playbook_dir }}/../../../../deploy/k8s/monitoring"
token_file: /root/.config/knaster/k3s-prometheus.token
ca_file: /root/.config/knaster/k3s-ca.crt
tasks:
- name: Manifeste anwenden
ansible.builtin.command: kubectl apply -f {{ manifests }}/{{ item }}
loop: [prometheus-access.yaml, kube-state-metrics.yaml]
register: apply
changed_when: "'configured' in apply.stdout or 'created' in apply.stdout"
- name: Warten, bis kube-state-metrics bereit ist
ansible.builtin.command: kubectl -n kube-system rollout status deployment/kube-state-metrics --timeout=180s
changed_when: false
- name: Token des ServiceAccounts prometheus-infra lesen (Secret wird vom Controller befüllt)
ansible.builtin.shell: >
set -o pipefail;
kubectl -n kube-system get secret prometheus-infra-token -o go-template='{{ "{{" }}.data.token{{ "}}" }}' | base64 -d
args: {executable: /bin/bash}
register: token
until: token.stdout | length > 0
retries: 10
delay: 2
changed_when: false
no_log: true
- name: Token als Datei auf ops ablegen (600, nie ausgeben)
ansible.builtin.copy:
content: "{{ token.stdout }}"
dest: "{{ token_file }}"
mode: "0600"
no_log: true
# Die kubelet-Zertifikate sind von k3s-server-ca signiert und tragen die Knoten-IP (19.10. geprüft).
- name: CA des Clusters lesen
ansible.builtin.shell: >
set -o pipefail;
kubectl -n kube-system get secret prometheus-infra-token -o go-template='{{ "{{" }}index .data "ca.crt"{{ "}}" }}' | base64 -d
args: {executable: /bin/bash}
register: ca
changed_when: false
- name: CA als Datei auf ops ablegen
ansible.builtin.copy:
content: "{{ ca.stdout }}\n"
dest: "{{ ca_file }}"
mode: "0600"
- name: Zugang prüfen (cAdvisor eines Knotens mit Token und CA)
ansible.builtin.shell: >
set -o pipefail;
ip=$(kubectl get node k3s -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}');
curl -fsS -m 10 --cacert {{ ca_file }} -H "Authorization: Bearer $(cat {{ token_file }})"
https://$ip:10250/metrics/cadvisor | grep -c '^container_memory_working_set_bytes'
args: {executable: /bin/bash}
register: probe
changed_when: false
- name: Ergebnis
ansible.builtin.debug:
msg: "cAdvisor auf k3s erreichbar, {{ probe.stdout }} Reihen container_memory_working_set_bytes"
- name: Infra-LXC – Prometheus, Ziele und Dashboard
hosts: infra
roles: [infra-stack]
@@ -24,6 +24,10 @@ infra_secrets: [POSTGRES_PASSWORD, KNASTER_API_TOKEN, GRAFANA_ADMIN_PASSWORD, GR
# Lese-Token monitoring@pve!prom (PVEAuditor) auf ops
infra_pve_exporter_env: /root/.config/knaster/pve-exporter.env
# Lesezugang zum kubelet für Prometheus (Task 6.5), auf ops von playbooks/monitoring-k3s.yml abgelegt
infra_k3s_token: /root/.config/knaster/k3s-prometheus.token
infra_k3s_ca: /root/.config/knaster/k3s-ca.crt
# file_sd: auf ops aus `tofu output -json gpu_vms` erzeugt (nicht im Repo)
infra_tofu_dir: "{{ playbook_dir }}/../../tofu"
infra_targets_dir: "{{ playbook_dir }}/../monitoring-targets.generated"
@@ -17,6 +17,7 @@
- {path: "{{ infra_repo_dir }}", mode: "0755"}
- {path: "{{ infra_state_dir }}", mode: "0700"}
- {path: "{{ infra_state_dir }}/secrets", mode: "0700"}
- {path: "{{ infra_state_dir }}/secrets/k3s", mode: "0755"}
# Nur die Teile, die Build und Konfiguration brauchen. Nie .git, .venv, tofu-State oder .env-Dateien.
- name: Repo-Auszug von ops abgleichen
@@ -87,6 +88,30 @@
mode: "0600"
no_log: true
# Task 6.5: Token des ServiceAccounts prometheus-infra und CA des Clusters (von playbooks/monitoring-k3s.yml
# auf ops abgelegt). Lesbar für nobody (Prometheus im Container). Fehlen sie, bleiben die k3s-Jobs down.
- name: k3s-Zugang für Prometheus vorhanden? (auf ops)
ansible.builtin.stat:
path: "{{ item }}"
loop: ["{{ infra_k3s_token }}", "{{ infra_k3s_ca }}"]
delegate_to: localhost
register: k3s_access
- name: k3s-Zugang für Prometheus kopieren
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ infra_state_dir }}/secrets/k3s/{{ item.dest }}"
owner: "65534"
group: "65534"
mode: "0400"
loop:
- {src: "{{ infra_k3s_token }}", dest: token}
- {src: "{{ infra_k3s_ca }}", dest: ca.crt}
loop_control:
label: "{{ item.dest }}"
when: k3s_access.results | map(attribute='stat.exists') | min
no_log: true
- name: file_sd-Ziele
ansible.builtin.include_tasks: targets.yml
@@ -1,11 +1,24 @@
# file_sd-Ziele der GPU-VMs (node, gpu, llamacpp). Auch einzeln aufrufbar: playbooks/monitoring-targets.yml
# (nach refresh-vm-access.sh, wenn sich DHCP-Adressen geändert haben). Prometheus liest die Dateien selbst neu.
# k3s (Task 6.5): kubelet und kube-state-metrics aus `kubectl get nodes` auf ops. Ist der Cluster nicht
# erreichbar, bleiben diese Listen leer und der Rest läuft weiter.
- name: k3s-Knoten lesen (auf ops)
ansible.builtin.shell: mkdir -p {{ infra_targets_dir }} && kubectl get nodes -o json > {{ infra_targets_dir }}/k3s-nodes.json
args:
executable: /bin/bash
delegate_to: localhost
run_once: true
register: k3s_nodes
failed_when: false
changed_when: false
- name: file_sd-Ziele aus tofu output erzeugen (auf ops)
ansible.builtin.shell: |
set -euo pipefail
tofu output -json gpu_vms | python3 {{ infra_repo_src }}/platform/proxmox/scripts/monitoring-targets.py \
--registry {{ infra_repo_src }}/sites/{{ knaster_site }}/registry.yaml --out {{ infra_targets_dir }} \
--llamacpp '{{ dict(_llamacpp_hosts | zip(_llamacpp_hosts | map('extract', hostvars, 'llamacpp_profiles'))) | to_json }}'
--llamacpp '{{ dict(_llamacpp_hosts | zip(_llamacpp_hosts | map('extract', hostvars, 'llamacpp_profiles'))) | to_json }}' \
{{ ('--k3s-nodes ' ~ infra_targets_dir ~ '/k3s-nodes.json') if k3s_nodes.rc == 0 else '' }}
args:
chdir: "{{ infra_tofu_dir }}"
executable: /bin/bash
@@ -27,4 +40,4 @@
src: "{{ infra_targets_dir }}/{{ item }}.json"
dest: "{{ infra_state_dir }}/file_sd/{{ item }}.json"
mode: "0644"
loop: [node, gpu, llamacpp]
loop: [node, gpu, llamacpp, kubelet, kube-state-metrics]