Mise à jour 2026-06 : cette stack a bien évolué depuis — logs centralisés, alerting réellement actif et annotations automatiques. L’évolution est retracée en fin d’article, et la mise en œuvre détaillée dans Observabilité v2.
Pourquoi VictoriaMetrics plutôt que Prometheus ?
Le premier Prometheus que j’ai déployé sur un master Pi 4 8 Go a fini par grignoter jusqu’à 2 Go de RAM — pour deux semaines de rétention et à peine une cinquantaine de cibles. Sur un nœud qui fait déjà tourner l’API server et etcd, c’est un quart de la capacité disponible réquisitionné par un seul composant de monitoring. Il fallait un outil pensé pour tourner à l’étroit.
VictoriaMetrics offre un ratio performances/ressources bien supérieur :
- Compression de données 5-10x meilleure que Prometheus
- Consommation mémoire ~70% inférieure à configuration équivalente
- Compatibilité totale avec les dashboards Grafana Prometheus
- API PromQL identique — zéro changement dans les dashboards existants
Pour un homelab sur ARM64, c’est le meilleur choix.
Architecture de la stack
vmagent (collecte)
│ scrape des cibles (pods, nodes, k8s API)
▼
VictoriaMetrics single-node (stockage)
│ TSDB compressée, rétention 30j
├──► Grafana (dashboards)
└──► VMAlert (règles d'alerte)
│
▼
Alertmanager (notifications)
vmagent est l’équivalent léger de Prometheus scrape — il collecte les métriques des cibles et les pousse vers VictoriaMetrics via le remote write protocol. Il consomme ~50 Mo de RAM.
Déploiement
VictoriaMetrics
apiVersion: apps/v1
kind: Deployment
metadata:
name: victoriametrics
namespace: monitoring
spec:
template:
spec:
containers:
- name: victoriametrics
image: victoriametrics/victoria-metrics:stable
args:
- -storageDataPath=/storage
- -retentionPeriod=30d
- -httpListenAddr=:8428
resources:
requests:
memory: 256Mi
limits:
memory: 1Gi
volumeMounts:
- name: storage
mountPath: /storage
30 jours de rétention avec ~50 cibles génère environ 3-4 Go de données compressées. Un PVC de 10 Go est largement suffisant.
vmagent — scraping Kubernetes
La configuration de scraping suit le format Prometheus. Les targets clés :
# ConfigMap vmagent-config
scrape_configs:
# Métriques des nœuds via node-exporter
- job_name: 'node-exporter'
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: '(.*):.*'
target_label: __address__
replacement: '${1}:9100'
# Métriques kubelet
- job_name: 'kubelet'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
# Pods avec annotation prometheus.io/scrape
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
Grafana
Grafana se connecte à VictoriaMetrics comme datasource Prometheus standard :
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-datasources
namespace: monitoring
data:
datasources.yaml: |
apiVersion: 1
datasources:
- name: VictoriaMetrics
type: prometheus
url: http://victoriametrics.monitoring.svc.cluster.local:8428
isDefault: true
Les dashboards Kubernetes standard (IDs Grafana : 315, 6417, 13332) fonctionnent sans modification.
Dashboards clés
Cluster Overview (Grafana 315) : vue globale CPU/RAM/réseau par nœud. Premier dashboard à consulter pour un état général.
Kubernetes Pods (Grafana 6417) : métriques par pod — idéal pour identifier les pods OOM-killés ou les containers qui consomment trop.
Longhorn : dashboard officiel Longhorn pour l’état des volumes et l’utilisation du stockage.
Node Exporter : métriques système détaillées par nœud (température CPU, I/O disque, saturation mémoire).
Alerting
⚠️ Ces règles existaient sur le papier — l’alerting réel (Alertmanager → Telegram) n’a été activé que des mois plus tard. Détails dans la mise à jour 2026-06.
VMAlert évalue les règles d’alerte et envoie les notifications via Alertmanager. Les alertes critiques configurées :
groups:
- name: homelab-critical
rules:
- alert: NodeMemoryHigh
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "Node {{ $labels.instance }} — mémoire disponible < 10%"
- alert: LonghornVolumeDegraded
expr: longhorn_volume_robustness != 2
for: 10m
labels:
severity: critical
annotations:
summary: "Volume Longhorn {{ $labels.volume }} dégradé"
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} en CrashLoop"
Mise à jour 2026-05-12 — Deadlock RWO sur Grafana
Grafana stocke sa base SQLite (dashboards custom, utilisateurs, plugins) sur un PVC Longhorn en accès RWO (ReadWriteOnce). Le Deployment par défaut utilise la stratégie RollingUpdate avec 1 surge et 0 unavailable. Lors d’un rolling update, le nouveau pod tentait de monter le même PVC RWO que l’ancien pod toujours en Terminating → AttachVolume bloqué → le rollout traînait 5+ minutes, parfois jusqu’au timeout.
Deux fixes appliqués (commits 4c02c9c + 917823a) :
1. Stratégie Recreate
spec:
strategy:
type: Recreate
Le nouveau pod attend que l’ancien soit complètement terminé avant de démarrer. Cela introduit une brève indisponibilité de Grafana (~30s), en échange d’un rollout déterministe et sans blocage. Pour un dashboard interne de homelab, c’est un compromis évident.
2. Memory limit 256Mi → 512Mi
Grafana avec defaultDashboardsEnabled: true (Helm chart) charge les dashboards en mémoire au démarrage et maintient les plugins actifs. À 256Mi de limit, des OOMKilled aléatoires survenaient lors de l’ouverture du dashboard k8s-cluster (30+ panels simultanés). Bump à 512Mi → stable.
resources:
requests:
memory: 100Mi
limits:
memory: 512Mi
Le requests reste à 100Mi pour ne pas sur-réserver sur les nœuds.
La leçon transposable : tout workload stateful sur PVC RWO doit avoir strategy: Recreate (ou un PVC RWX si le storage le permet). Le combo “RollingUpdate + RWO” est un piège silencieux — ça marche les jours où on a de la chance, et bloque les autres.
Leçons apprises
node-exporter sur chaque nœud : déployer node-exporter via DaemonSet (pas Deployment) pour garantir une instance sur chaque nœud, y compris les futurs. Sans node-exporter, les métriques système sont absentes — seules les métriques Kubernetes sont disponibles.
Rétention vs stockage : 30 jours de rétention est un bon équilibre. Au-delà, la croissance du PVC devient significative. Pour l’archivage long terme, configurer VictoriaMetrics pour écrire en remote write vers MinIO (format compatible S3).
insecure_skip_verify: true pour kubelet : le certificat kubelet est auto-signé. L’alternative correcte est de configurer une CA trust chain — acceptable pour un homelab, mais à corriger pour un environnement de production.
Mise à jour 2026-06-12 — La v2 : logs, alerting réel, annotations
Honnêteté rétrospective : la section « Alerting » ci-dessus décrivait la cible plus que la réalité. vmalert et Alertmanager sont restés inactifs pendant des mois — les règles existaient sur le papier, rien ne notifiait personne. Et la rétention réelle s’est stabilisée à 15 jours (pas 30) : suffisant pour le diagnostic, deux fois moins de stockage.
Ce qui a fini par tout débloquer : un pic de load inattribuable lors d’un audit — aucune métrique par pod, pas de logs centralisés, pas d’alerte. Les quatre manques ont été comblés en une journée :
~317 Mi RAM, ça tient sur des Pi
Mais : un pic de load reste inexpliqué — pas de métriques par pod, pas de logs, alerting inactif.
~360k lignes ingérées en 2 min
Corrélation logs ↔ métriques dans Grafana, même time range — fini le SSH sur chaque nœud.
le cluster me parle, enfin
Events K8s Warning et déploiements ArgoCD directement sur les graphes — chaque pic a son contexte.
Le détail de la mise en œuvre (VictoriaLogs + Vector, vmalert → Alertmanager → Telegram, annotations automatiques des graphes, et la leçon « pending n’est pas firing » sur les probes qui flappent) : Observabilité v2 — logs, alertes & annotations en une journée.