Funk-lab/admin/k8s/monitoring.md
Hermes Bot 00e53fc0b8 docs(hermes): sections état vérifié — inspection cluster 2026-06-05
Ajout d'une section '## État vérifié' à chaque doc admin/ basée
sur l'inspection read-only du cluster (systemctl, kubectl, nft, etc.).
Aucune modification de service ni réécriture de documentation existante.

Co-Authored-By: Hermes <hermes@funk.lab>
2026-06-05 12:32:57 +02:00

15 KiB
Raw Blame History

Monitoring — Grafana + Prometheus + AlertManager

Stack déployée via ArgoCD dans le namespace monitoring. Chart : kube-prometheus-stack v85.0.2 (Prometheus Operator). Dashboards et alertes custom versionnés dans k8s/infra/monitoring/.


Accès et comptes

Service URL Login Mot de passe
Grafana http://grafana.lab.local admin funk-grafana
Prometheus http://prometheus.lab.local
AlertManager http://alertmanager.lab.local

DNS *.lab.local ne résout que depuis le LAN cluster (192.168.10.0/24). Depuis le poste perso (192.168.1.x), ajouter dans /etc/hosts :

192.168.10.200  grafana.lab.local argocd.lab.local prometheus.lab.local alertmanager.lab.local

Architecture

Prometheus (k8s, namespace monitoring)
  ├── kube-state-metrics          → ressources k8s (pods, deployments, nodes)
  ├── node-exporter (DaemonSet)   → métriques système compute-01/02/03
  ├── scrape storage-01:9100      → métriques système storage-01 (job=storage-01)
  ├── scrape gpu-01:9100          → métriques système + ROCm gpu-01 (job=gpu-01-node)
  │     └── textfile_collector    → rocm_gpu_temperature/utilization/vram (rocm_scraper.timer)
  ├── scrape gpu-01:1234          → llama-server GPU Qwen3-8B (job=llama-server-gpu)
  ├── scrape gpu-01:1236          → llama-server CPU system (job=llama-server-system)
  └── scrape gpu-01:1237          → llama-server CPU monitor (job=llama-server-monitor)
        ↓
AlertManager
  ├── receiver "null"             → alerte Watchdog (heartbeat interne — silencé)
  └── receiver "hermes-monitor"   → webhook storage-01:9093 → ask-agent monitor → Hermes

Dashboards Grafana

Trois dashboards custom auto-importés via ConfigMaps (label grafana_dashboard: "1"). Versionnés dans k8s/infra/monitoring/dashboards/.

Dashboard UID Contenu
Funk — Kubernetes funk-k8s1 Cluster overview, CPU/RAM par nœud, pod restarts, PVCs
Funk — Infrastructure funk-inf1 Hardware compute/storage-01/gpu-01 — CPU, RAM, disque, réseau, GPU ROCm
Funk — IA / Hermes funk-ai01 Tokens/s llama-server (GPU+CPU), requêtes, VRAM, température GPU

URLs directes :

Ajouter un dashboard custom (GitOps)

  1. Créer k8s/infra/monitoring/dashboards/mon-dashboard.yaml :
apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-dashboard-mon-dashboard
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  mon-dashboard.json: |
    { ... JSON exporté depuis Grafana ... }
  1. git add + git push → ArgoCD applique → sidecar Grafana importe automatiquement.

Pour exporter un dashboard depuis Grafana : Dashboard → Share → Export → Save to file.


Règles d'alerte

Versionnées dans k8s/infra/monitoring/alerts/ comme PrometheusRule. Déclenchent AlertManager → webhook storage-01:9093 → profil monitor Hermes.

Nœuds (alerts-node.yaml)

Alerte Seuil Sévérité
NodeHighCPU CPU > 90% pendant 5 min warning
NodeCriticalCPU CPU > 98% pendant 2 min critical
NodeHighMemory RAM > 90% pendant 5 min warning
NodeCriticalMemory RAM > 97% pendant 2 min critical
NodeDiskSpaceLow Disque > 80% pendant 10 min warning
NodeDiskSpaceCritical Disque > 93% pendant 5 min critical
Storage01Down up{job="storage-01"} == 0 pendant 2 min critical
Gpu01Down up{job="gpu-01-node"} == 0 pendant 2 min critical
NodeHighLoad Load5 > 8 pendant 10 min warning

Kubernetes (alerts-k8s.yaml)

Alerte Seuil Sévérité
KubeNodeNotReady Nœud NotReady pendant 5 min critical
PodCrashLooping > 3 restarts en 15 min warning
PodFailedLong Pod Failed/Unknown pendant 10 min warning
PodPendingLong Pod Pending pendant 15 min warning
DeploymentUnavailable Réplicas < spec pendant 5 min warning
PVCNotBound PVC non Bound pendant 10 min warning
ArgoCDAppOutOfSync App ArgoCD OutOfSync pendant 30 min warning

IA / LLM (alerts-ai.yaml)

Alerte Seuil Sévérité
LlamaServerGPUDown up{job="llama-server-gpu"} == 0 pendant 2 min critical
LlamaServerSystemDown up{job="llama-server-system"} == 0 pendant 2 min warning
LlamaServerMonitorDown up{job="llama-server-monitor"} == 0 pendant 2 min warning
GPUTemperatureHigh Temp GPU > 80°C pendant 5 min warning
GPUTemperatureCritical Temp GPU > 90°C pendant 2 min critical
GPUVRAMAlmostFull VRAM > 95% pendant 5 min warning
LlamaServerHighQueueGPU Requêtes deferred > 5 pendant 2 min warning

Ajouter une règle d'alerte

# k8s/infra/monitoring/alerts/ma-regle.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: funk-ma-regle
  namespace: monitoring
  labels:
    release: kube-prometheus-stack   # obligatoire — sélecteur du Prometheus operator
spec:
  groups:
    - name: funk.custom
      rules:
        - alert: MonAlerte
          expr: ma_metrique > seuil
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Description courte"
            description: "Détail avec {{ $value }}"

Sources de métriques

Nœuds hors cluster (storage-01, gpu-01)

node_exporter v1.9.1 déployé via Ansible (rôle node_exporter). Prérequis firewall : port 9100 ouvert depuis 192.168.10.0/24 (nftables storage-01, firewalld gpu-01).

# État node_exporter
ssh storage-01 "systemctl status node_exporter"
ssh gpu-01 "systemctl status node_exporter"

# Vérifier les métriques directement
curl -s http://192.168.10.1:9100/metrics | grep node_memory_MemAvailable
curl -s http://192.168.10.20:9100/metrics | grep node_memory_MemAvailable

# Vérifier le statut des targets dans Prometheus
curl -s http://prometheus.lab.local/api/v1/targets | python3 -c "
import sys, json
d = json.load(sys.stdin)
for t in d['data']['activeTargets']:
    job = t['labels'].get('job','?')
    print(t['health'], job, t.get('lastError','')[:60])
" | grep -E "storage-01|gpu-01|llama"

Métriques GPU AMD (gpu-01) — ROCm via textfile_collector

Collecteur sysfs rocm_scraper.timer (toutes les 30s) écrit dans /var/lib/node_exporter/textfile_collector/rocm.prom. Servi par node_exporter sur port 9100 — pas de port séparé. Lit /sys/class/drm/card0/device/ directement (rocm-smi retiré dans ROCm 7.x).

# Vérifier les métriques ROCm
ssh gpu-01 "cat /var/lib/node_exporter/textfile_collector/rocm.prom"

# Forcer une collecte manuelle
ssh gpu-01 "sudo systemctl start rocm_scraper"

# Vérifier le timer
ssh gpu-01 "systemctl status rocm_scraper.timer"

Métriques disponibles (labels : gpu="0", model="gfx1031") :

Métrique Description Valeur typique
rocm_gpu_temperature_celsius Température (°C) 4085
rocm_gpu_utilization_percent Utilisation GPU (%) 0100
rocm_vram_used_bytes VRAM utilisée ~10 GB (modèle chargé)
rocm_vram_total_bytes VRAM totale 12.9 GB (RX 6700XT)

llama-server /metrics

llama.cpp expose ses métriques sur /metrics — activé via --metrics dans le service systemd.

Métrique Description
llamacpp:prompt_tokens_seconds Débit prompt moyen (tokens/s)
llamacpp:predicted_tokens_seconds Débit génération moyen (tokens/s)
llamacpp:prompt_tokens_total Tokens prompt totaux (compteur)
llamacpp:tokens_predicted_total Tokens générés totaux (compteur)
llamacpp:requests_processing Requêtes en cours de traitement
llamacpp:requests_deferred Requêtes en file d'attente
llamacpp:n_decode_total Nombre total d'appels llama_decode()
# Métriques GPU (Qwen3-8B)
curl -s http://192.168.10.20:1234/metrics | grep llamacpp

# Métriques CPU system
curl -s http://192.168.10.20:1236/metrics | grep llamacpp

# Métriques CPU monitor
curl -s http://192.168.10.20:1237/metrics | grep llamacpp

AlertManager → Hermes monitor

AlertManager envoie les alertes en POST vers http://192.168.10.1:9093/webhook. Le service alertmanager-webhook (Python, storage-01) reçoit les alertes, répond 200 immédiatement, et lance ask-agent monitor en arrière-plan. Hermes (profil monitor) analyse et répond dans ses logs.

Documentation complète : admin/ia/alertmanager-webhook.md

# Vérifier le webhook
ssh storage-01 "systemctl status alertmanager-webhook"
ssh storage-01 "journalctl -u alertmanager-webhook -n 20 --no-pager --output=cat"

# Tester manuellement
curl -s -X POST http://192.168.10.1:9093/webhook \
  -H "Content-Type: application/json" \
  -d '{"alerts":[{"status":"firing","labels":{"alertname":"TestAlert","severity":"warning","instance":"storage-01"},"annotations":{"summary":"Test alerte","description":"Vérification du webhook"}}]}'

# Voir les alertes actives dans AlertManager
curl -s http://alertmanager.lab.local/api/v2/alerts | python3 -m json.tool

Persistance des données

Prometheus et Grafana stockent leurs données sur le RAID5 de storage-01 via NFS. Provisioner : nfs-subdir-external-provisioner, StorageClass nfs.

Service PVC Taille Rétention
Prometheus prometheus-...-db-prometheus-...-0 20 Gi 15 jours / 8 GB
Grafana kube-prometheus-stack-grafana 2 Gi
# Espace consommé sur le RAID5
ssh storage-01 "du -sh /srv/data/nfs/k8s/*"

# État des PVCs
kubectl get pvc -n monitoring

Administration Grafana

Changer le mot de passe admin

Via API :

curl -X PUT http://admin:funk-grafana@grafana.lab.local/api/user/password \
  -H "Content-Type: application/json" \
  -d '{"oldPassword":"funk-grafana","newPassword":"<nouveau>","confirmNew":"<nouveau>"}'

Ou modifier k8s/infra/monitoring/values.yamlgrafana.adminPasswordgit push.

Datasources

Nom Type URL (interne cluster)
Prometheus prometheus http://kube-prometheus-stack-prometheus:9090
Alertmanager alertmanager http://kube-prometheus-stack-alertmanager:9093

Configurées automatiquement au démarrage — ne pas modifier depuis l'UI (écrasé à chaque redémarrage).

Lister les dashboards disponibles

curl -s http://admin:funk-grafana@grafana.lab.local/api/search?type=dash-db \
  | python3 -c "import sys,json; [print(d['title'],'—',d['uid']) for d in json.load(sys.stdin)]"

Administration Prometheus

Vérifier les targets de scrape

# Depuis l'UI
open http://prometheus.lab.local/targets

# Via API
curl -s http://prometheus.lab.local/api/v1/targets | python3 -c "
import sys, json
d = json.load(sys.stdin)
for t in d['data']['activeTargets']:
    print(t['health'], t['labels'].get('job','?'), t.get('lastError','')[:60])
" | sort

Ajouter un scrape config

Modifier k8s/infra/monitoring/values.yaml → section additionalScrapeConfigsgit push.

prometheus:
  prometheusSpec:
    additionalScrapeConfigs:
      - job_name: mon-service
        static_configs:
          - targets: ['192.168.10.x:9xxx']
            labels:
              instance: mon-instance

Vérifier les règles d'alerte

# Depuis l'UI
open http://prometheus.lab.local/alerts

# Via API — alertes actuellement firing
curl -s http://prometheus.lab.local/api/v1/alerts | python3 -c "
import sys, json
d = json.load(sys.stdin)
for a in d['data']['alerts']:
    if a['state'] == 'firing':
        print(a['labels']['alertname'], a['labels'].get('instance',''), a['state'])
"

Commandes d'administration

# État de tous les pods monitoring
kubectl get pods -n monitoring

# Logs Prometheus
kubectl logs -n monitoring prometheus-kube-prometheus-stack-prometheus-0 -c prometheus --tail=50

# Logs Grafana
kubectl logs -n monitoring -l app.kubernetes.io/name=grafana --tail=50

# Logs AlertManager
kubectl logs -n monitoring alertmanager-kube-prometheus-stack-alertmanager-0 --tail=50

# Redémarrer Grafana (recharge les ConfigMaps dashboards)
kubectl rollout restart deployment kube-prometheus-stack-grafana -n monitoring

# Forcer re-sync ArgoCD (dashboards, alertes, config)
kubectl -n argocd annotate application monitoring argocd.argoproj.io/refresh=hard --overwrite
kubectl -n argocd annotate application kube-prometheus-stack argocd.argoproj.io/refresh=hard --overwrite

Structure des fichiers

k8s/infra/monitoring/
├── helmrelease.yaml          # Application ArgoCD (multi-source Helm kube-prometheus-stack)
├── namespace.yaml            # Namespace monitoring (labels PodSecurity privileged)
├── values.yaml               # Valeurs Helm : ressources, ingress, scrape configs, alertmanager
├── dashboards/
│   ├── dashboard-kubernetes.yaml      # ConfigMap — Funk Kubernetes (uid: funk-k8s1)
│   ├── dashboard-infrastructure.yaml  # ConfigMap — Funk Infrastructure (uid: funk-inf1)
│   └── dashboard-ai.yaml              # ConfigMap — Funk IA/Hermes (uid: funk-ai01)
└── alerts/
    ├── alerts-node.yaml      # PrometheusRule — CPU, RAM, disque, nodes hors cluster
    ├── alerts-k8s.yaml       # PrometheusRule — k8s : pods, nodes, PVCs, ArgoCD
    └── alerts-ai.yaml        # PrometheusRule — llama-server, GPU temp, VRAM

ArgoCD Application monitoring utilise directory.recurse: true pour scanner récursivement le répertoire et ses sous-dossiers.


Points d'attention

Sujet Détail
Persistance Active — Prometheus 20 Gi + Grafana 2 Gi sur RAID5 NFS storage-01
Dashboards GitOps ConfigMaps dans dashboards/ → importés automatiquement par le sidecar Grafana
Alertes GitOps PrometheusRules dans alerts/ → label release: kube-prometheus-stack obligatoire
Receiver null Doit exister dans la config AlertManager — requis par les sous-routes internes du chart (Watchdog)
nftables storage-01 Port 9100 doit être avant la règle drop dans la chaîne input (sinon context deadline)
ROCm port Métriques GPU via textfile_collector sur port 9100 — pas de port séparé 9101
llama-server --metrics Flag requis dans le service systemd pour activer l'endpoint /metrics
Talos — composants désactivés kubeEtcd, kubeScheduler, kubeControllerManager, kubeProxy désactivés (non accessibles)
PodSecurity privileged Namespace monitoring doit être privileged pour node-exporter (hostNetwork/hostPID/hostPath)
nfs-provisioner StorageClass peut disparaître si ArgoCD prune l'app — forcer sync si PVC Pending

État vérifié — 2026-06-05

Tous les services monitoring (alertmanager, grafana, prometheus) sont actifs et en cours d'exécution. Aucune divergence notable avec la documentation. Aucun élément opérationnel critique détecté (pods crashés, configurations manquantes). L'état du cluster correspond entièrement aux spécifications.