Un serveur sans surveillance est un serveur aveugle. Vous ne savez pas quand le disque se remplit, quel conteneur consomme trop de RAM, ou combien de requêtes 404 votre site génère. Cet article documente comment j’ai configuré la pile complète : Prometheus + Node Exporter + Grafana + Loki + Promtail.
L’architecture#
[Servidor doméstico]
├── node-exporter → métricas del sistema (CPU, RAM, disco, red)
├── docker-stats- → métricas de contenedores (textfile collector)
│ collector
├── prometheus → recolecta y almacena métricas
├── loki → agrega y almacena logs
├── promtail → envía logs de Nginx y syslog a Loki
└── grafana → dashboards de todo lo anteriorTous les services tournent sur Docker, coordonnés par le même docker-compose.yml.
Métriques système : Node Exporter#
Node Exporter expose les métriques du matériel et du SE. L’astuce : il doit tourner avec network_mode: host pour voir les vraies interfaces réseau du serveur. S’il tourne en réseau Docker, il ne voit que l’interface eth0 du conteneur.
node-exporter:
image: prom/node-exporter:v1.8.2
network_mode: host
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
- ./textfile-collector:/textfile:ro
command:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/rootfs
- --web.listen-address=127.0.0.1:9100
- --collector.textfile.directory=/textfileIl écoute sur 127.0.0.1:9100. Prometheus l’atteint par 172.17.0.1:9100 (l’IP de l’hôte depuis le réseau Docker).
Métriques de conteneurs : docker stats + textfile collector#
Le problème avec cAdvisor est qu’il ne fonctionne pas avec Docker 29 et le driver de stockage overlayfs en cgroupv2 — il échoue avec “failed to identify read-write layer ID”.
La solution : un conteneur léger qui exécute docker stats toutes les 30 secondes et écrit le résultat au format Prometheus dans un fichier que Node Exporter lit.
#!/bin/bash
# docker_stats.sh
OUTFILE="/textfile/docker_stats.prom"
TMPFILE="${OUTFILE}.tmp"
{
echo "# HELP docker_container_cpu_percent CPU usage percentage per container"
echo "# TYPE docker_container_cpu_percent gauge"
# ... más definiciones ...
docker stats --no-stream --format \
'{{.Name}}|{{.CPUPerc}}|{{.MemUsage}}|{{.NetIO}}' 2>/dev/null | \
while IFS='|' read -r name cpu mem net; do
cpu_val=$(echo "$cpu" | tr -d '%' | tr ',' '.')
# ... conversión de unidades ...
echo "docker_container_cpu_percent{name=\"${name}\"} ${cpu_val}"
echo "docker_container_memory_bytes{name=\"${name}\"} ${mem_used_bytes}"
echo "docker_container_running{name=\"${name}\"} 1"
done
# Contenedores parados
docker ps -a --filter "status=exited" --format '{{.Names}}' 2>/dev/null | \
while read -r name; do
echo "docker_container_running{name=\"${name}\"} 0"
done
} > "$TMPFILE" && mv "$TMPFILE" "$OUTFILE"L’écriture atomique (tmp → final) empêche Prometheus de lire un fichier à moitié.
docker-stats-collector:
image: docker:27-cli
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./textfile-collector:/textfile
- ./docker_stats.sh:/docker_stats.sh:ro
entrypoint: sh -c "apk add --no-cache bc > /dev/null 2>&1; while true; do sh /docker_stats.sh; sleep 30; done"Prometheus : collecter et conserver#
prometheus:
image: prom/prometheus:v2.51.2
networks:
- monitoring
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=30d
- --web.enable-lifecycleConfiguration du scraping :
global:
scrape_interval: 15s
scrape_configs:
- job_name: prometheus
static_configs:
- targets: [localhost:9090]
- job_name: node
static_configs:
- targets: [172.17.0.1:9100]
relabel_configs:
- target_label: host
replacement: servidor-casa172.17.0.1 est l’IP de l’hôte accessible depuis le réseau Docker bridge. Les données sont conservées 30 jours.
Logs : Loki + Promtail#
Loki stocke les logs sans indexer le contenu complet — uniquement les étiquettes (labels). Promtail les collecte et les envoie avec des étiquettes comme job, host, filename.
promtail:
image: grafana/promtail:3.3.2
user: root
networks:
- monitoring
volumes:
- ./promtail-config.yml:/etc/promtail/config.yml:ro
- ./promtail-data:/tmp/promtail
- ~/infra/web/logs:/logs/nginx:ro
- /var/log:/logs/host:roIl doit tourner en root pour lire /var/log.
Grafana : dashboards#
Grafana se connecte à Prometheus et Loki comme sources de données. Les dashboards les plus utiles :
Système (Node Exporter) :
- CPU total et par cœur
- RAM utilisée / libre / cache
- Disque : utilisation par partition, IOPS, débit
- Réseau : trafic entrant/sortant par interface
Conteneurs (docker stats) :
- CPU % par conteneur
- RAM par conteneur vs limite
- État (running/stopped)
- Trafic réseau par conteneur
Logs (Loki) :
- Logs Nginx en temps réel
- Requêtes par code de statut (200, 301, 404, 500)
- Top des IPs avec le plus de requêtes
- Top des routes les plus accédées
Problème : [$__range] dans les requêtes instantanées de Loki#
Lors de l’utilisation de panneaux de type “stat” ou “piechart” avec Loki, la variable [$__range] ne se résout pas — Grafana renvoie “empty duration string”. La solution est d’utiliser une durée fixe :
# MAL (en paneles stat/piechart):
sum by(status) (count_over_time({job="nginx"} | pattern ... [$__range]))
# BIEN:
sum by(status) (count_over_time({job="nginx"} | pattern ... [24h]))Les panneaux de type “time series” acceptent correctement [$__interval].
Sécurité de la pile#
- Prometheus et Loki n’ont pas d’accès externe — uniquement sur le réseau interne
monitoring - Grafana est le seul point d’accès, protégé avec Traefik et Let’s Encrypt
GF_AUTH_ANONYMOUS_ENABLED=falseetGF_USERS_ALLOW_SIGN_UP=falsedans Grafana- Node Exporter écoute uniquement sur
127.0.0.1, non exposé sur toutes les interfaces
Résultat#
Avec cette stack, tu as une visibilité complète du serveur : quels processus consomment des ressources, quels conteneurs échouent, quelles requêtes reçoit ton web et quelles erreurs il génère. Tout dans des dashboards accessibles depuis monitor.serviciosrogeliowar.com.
Équipement recommandé#
- Raspberry Pi 3 B+ — Serveur léger à faible consommation pour commencer ton homelab
- Raspberry Pi 4 (4GB) — La base parfaite pour homelab, Docker et monitoring
Liens d’affiliation. Aucun coût supplémentaire pour toi.