
🌐 Aussi en: English · Deutsch · Español
Deep Dive de la série autour de l’Ansible Tour. Niveau : administration Linux avancée. Le tour explique les rôles ; les deep dives expliquent la technique en dessous – comment elle fonctionne, pourquoi elle est là, ce que cette installation en fait exactement, comment l’exploiter au quotidien et ce qui aurait existé d’autre.
Chaque serveur ici a son propre Prometheus et son propre Grafana (la partie 6 du tour présente les rôles). Cet article est le guide de lecture : ce que sont les chiffres, à quoi ressemble la normale sur ces machines, quels panneaux comptent quand quelque chose ne va pas – et comment l’alerte est construite, y compris l’erreur qui l’a rendue muette pendant des semaines.
🧭 Comment fonctionnent Prometheus et Grafana
Pull, séries temporelles, labels
Les exporteurs sont de petits programmes qui exposent des chiffres en HTTP – le node exporter pour l’hôte, mysqld_exporter pour MariaDB, php-fpm_exporter pour PHP, cAdvisor dans le kubelet pour les conteneurs, kube-state-metrics pour les objets Kubernetes. Prometheus les récupère (« scrape ») toutes les 15 secondes et enregistre chaque chiffre comme une série temporelle, identifiée par un nom et des labels comme container="nextcloud-fpm". Grafana interroge Prometheus dans son langage PromQL et dessine la réponse.
Trois fonctions qui couvrent la plupart des panneaux
rate(x[5m]): augmentation par seconde d’un compteur, moyennée sur cinq minutes – requêtes par seconde, secondes CPU par seconde (= cœurs).increase(x[1h]): de combien un compteur a crû en une heure – redémarrages, OOM kills, périodes bridées.max_over_time(…[7d])etsum by (…): la pire valeur sur une période, et l’addition de séries selon des labels choisis. C’est avec la seconde que se produisent la plupart des erreurs de lecture (voir plus bas).
Des alertes sans Alertmanager
Grafana évalue lui-même les règles d’alerte : une requête (A), un seuil (B), une durée (« pendant 5 minutes »). Si la condition tient assez longtemps, il envoie un mail au point de contact. Pour un administrateur et trois serveurs, cela remplace un Alertmanager séparé.
🛡️ Pourquoi il est là
- Des tendances au lieu d’instants. 30 jours d’historique répondent à « depuis quand ? » et « est-ce normal ? », ce que
topne peut jamais faire. - Un seul endroit pour l’hôte, la base, PHP, les conteneurs – et, depuis octobre 2026, les journaux à côté (Loki).
- Ouvert et standard. Prometheus et Grafana sont la langue de la supervision Kubernetes ; des tableaux de bord existent déjà pour chaque exporteur.
🔧 Ce que fait ce dépôt
| Élément | Détail |
|---|---|
| Prometheus | common_prometheus : intervalle de 15 s, 30 jours de rétention, écoute sur 127.0.0.1 ; 5 jobs de collecte par serveur, ~7 500 séries, 0,5 à 0,8 Go sur disque |
| Grafana | common_grafana : paquet du dépôt Grafana, derrière l’ingress sous /grafana, port 3000 ouvert seulement pour le nœud lui-même ; niveau de journal warn |
| Sources de données | Prometheus et Loki, créées par l’API avec des UID fixes |
| Tableaux de bord | 1860 Node Exporter Full, 7362 MySQL Overview, 4912 PHP-FPM, plus le « Container-Ressourcen » maison |
| Alertes | 11 règles sur les métriques et 4 sur les journaux, un point de contact par mail |
| Durcissement | domaine SELinux propre pour Grafana, Prometheus et les exporteurs ; connexion à Grafana protégée par une jail fail2ban et le verrouillage propre de Grafana |
Tout est provisionné par l’API HTTP de Grafana, au moyen de petits scripts Python qu’Ansible écrit et exécute. Les tableaux de bord sont importés avec des UID fixes, pour que liens et favoris survivent à une réimportation ; le tableau 1860 reçoit en plus un correctif de ses variables, car l’API d’import laisse sa source de données et ses variables node/job non initialisées, et chaque panneau affichait « No data » à la première ouverture.
📊 Lire les tableaux de bord
Node Exporter Full (1860) – l’hôte
| Panneau | Normal ici | Regarder de plus près quand |
|---|---|---|
| CPU Busy | en moyenne 5 % (blog), 9 % et 16 % (Nextcloud) ; 95e centile sous 30 % | durablement au-dessus de 70 % – « CPU Basic » montre alors si c’est user, system ou iowait |
| Sys Load | sous le nombre de cœurs, de courts pics légèrement au-dessus (redémarrage, analyses nocturnes) | au-dessus du nombre de cœurs pendant plus de quelques minutes |
| RAM Used | 16 à 32 % en moyenne, au plus 39 % | monte pendant des jours sans redescendre – une fuite, pas de la charge |
| SWAP Used | proche de zéro | croît régulièrement |
| Root FS Used | nettement sous 80 % | l’alerte se déclenche à 80 % |
| Disk IOps / Read/Write | de courts pics la nuit (analyses, redémarrage) | un iowait élevé avec beaucoup d’E/S en journée |
| Network Traffic | faible, des pics dus aux envois et aux sauvegardes | un trafic sortant durable que personne ne sait expliquer |
Un motif se répète chaque nuit : un trou de quelques minutes vers 03:30. Ce n’est pas une panne mais le redémarrage prévu après les mises à jour ; un trou à tout autre moment mérite un coup d’œil. Et le plus grand serveur Nextcloud montre pour K3s lui-même plusieurs fois le temps CPU du blog, pour le même travail – une propriété de sa génération de processeur, expliquée dans le deep dive K3s, pas une erreur de configuration.
MySQL Overview (7362) – la base
| Panneau | Normal ici | Regarder de plus près quand |
|---|---|---|
| MySQL Connections | une poignée, pics de 6 à 15 | proche de max_connections (50) |
| MySQL Questions / Queries | quelques dizaines par seconde, suit l’heure de la journée | un saut sans plus d’utilisateurs |
| InnoDB Buffer Pool | une grande part inutilisée, taux de succès > 99 % | pages libres proches de zéro et lectures disque en hausse |
| Temporary Objects | quelques tables temporaires sur disque (colonnes TEXT) | les tables sur disque croissent plus vite que les requêtes |
| Slow Queries | 0 | tout ce qui dépasse zéro – le slow log dit alors lesquelles |
PHP-FPM (4912) – les workers
| Panneau | Normal ici | Regarder de plus près quand |
|---|---|---|
| Active / idle processes | quelques actifs, la plupart inactifs | les actifs approchent max_children |
| Listen queue | 0 | au-dessus de zéro pendant plus d’une minute |
| Max children reached | 0 | augmente – le pool est trop petit |
| Slow requests | 0 | augmente – le journal du pod nomme le script |
Container-Ressourcen – le tableau de bord maison
Huit panneaux par namespace : CPU et mémoire en part de la limite du conteneur, bridage CPU, cœurs et working set en absolu, redémarrages et OOM kills par heure, la dernière raison d’arrêt par conteneur, et les limites et requests configurées. Il répond à la seule question que les autres tableaux de bord ne peuvent pas trancher : un conteneur est-il freiné par sa propre limite alors que l’hôte a de la marge ? Quelques pour cent de bridage sont normaux pour du PHP par à-coups ; un conteneur bridé à plus de 50 % est celui à qui il faut donner plus de CPU.
L’erreur de lecture
En écrivant le deep dive sur les performances, une requête pour le conteneur PHP du blog a montré un pic mémoire de 940 Mio pour une limite de 1 Gio. Elle avait additionné toutes les séries portant ce nom de conteneur – pendant un déploiement, l’ancien et le nouveau pod se chevauchent, et après un redémarrage cAdvisor rapporte brièvement l’ancien et le nouveau cgroup. Le vrai pic d’un seul pod était de 538 Mio. Les panneaux qui calculent sum by (namespace, pod, container), comme le tableau de bord maison, sont sûrs ; un sum sur le seul nom du conteneur ne l’est pas.
🚨 Les alertes – et pourquoi elles étaient muettes
| Alerte | Se déclenche quand (pendant 5 min) |
|---|---|
| Disque root / disque data | plus de 80 % occupés |
| Mémoire | plus de 90 % occupés |
| Charge CPU | plus de 85 % d’occupation |
| Nœud tombé | le node exporter ne répond pas |
| Mémoire de conteneur | un conteneur au-dessus de 90 % de sa limite mémoire |
| Bridage de conteneur | plus de 50 % des périodes CPU bridées |
| OOM de conteneur / boucle de crash | un OOM kill, ou plus de 2 redémarrages en 15 minutes |
| Trivy périmé / en échec | aucune analyse de vulnérabilités depuis 36 heures, ou la dernière a échoué |
| Journaux (Loki) | refus SELinux en mode enforcing, erreur fail2ban, OOM du noyau, plus aucun journal |
En septembre 2026, une vérification sur le plus grand serveur Nextcloud a montré qu’aucune de ces règles ne s’était jamais déclenchée – non parce que rien ne s’était passé, mais parce qu’elles ne le pouvaient pas. Les règles avaient été créées par l’API sans le champ condition, qui désigne la requête qui décide de l’alerte. Grafana écrivait « condition must not be empty » à chaque évaluation, et les règles étaient réglées sur execErrState: OK, ce qui transformait chaque erreur d’évaluation en « tout va bien ». Deux réglages, chacun raisonnable en soi, faisaient ensemble paraître l’alerte en bonne santé alors qu’elle était morte. Depuis, chaque règle indique condition: "B". La leçon : après un changement, vérifier l’état de chaque règle dans Grafana – « Normal » sans erreur d’évaluation – au lieu de prendre l’absence de mail pour une preuve.
Une lacune reste voulue : noDataState et execErrState sont toujours sur OK, pour qu’un redémarrage de Prometheus n’envoie pas une douzaine de mails. Si Prometheus lui-même s’arrêtait, toutes les règles resteraient tranquillement au vert. Ce cas est couvert hors de Grafana : Monit surveille Prometheus, Grafana, les exporteurs node et MySQL, Loki et Alloy, et envoie un mail si l’un d’eux s’arrête.
🧰 Exploitation au quotidien
# Prometheus directly, from the host
curl -s 'http://127.0.0.1:9090/api/v1/targets' | jq '.data.activeTargets[] | {job: .labels.job, health}'
curl -s --get 'http://127.0.0.1:9090/api/v1/query' \
--data-urlencode 'query=max_over_time(sum(phpfpm_active_processes)[7d:1m])' | jq '.data.result'
# Grafana state
systemctl status grafana-server prometheus
journalctl -u grafana-server --since -1h # warnings and errors only (log level warn)- Changer un seuil, c’est le changer dans le rôle et lancer le playbook ; une modification faite dans l’interface web serait écrasée au passage suivant, et c’est voulu.
- Un nouveau panneau destiné à rester va dans le JSON du tableau de bord dans le dépôt (le tableau maison) – pour les tableaux communautaires importés, dans une copie avec son propre UID.
- Sauvegardes : tout ce qui compte – sources de données, tableaux de bord, règles d’alerte – est recréé depuis le dépôt. Les métriques elles-mêmes ne sont pas sauvegardées ; 30 jours d’historique, c’est l’horizon voulu.
🆘 Antisèche : symptôme → commande
La version courte de cet article, pour le moment où quelque chose ne va pas. À lancer sur l’hôte en root ; <…> sont des espaces réservés.
| Symptôme | Commande |
|---|---|
| Grafana ou Prometheus injoignable | systemctl status grafana-server prometheus |
| 403 sur /grafana | # country filter in the ingress: is the address in the list? |
| Un graphique est vide | curl -s http://127.0.0.1:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, health}' |
| Interroger Prometheus directement | curl -s --get http://127.0.0.1:9090/api/v1/query --data-urlencode 'query=up' | jq '.data.result' |
| Pas de mail d’alerte alors que quelque chose ne va pas | # Grafana → Alerting → Alert rules: state "Error" or "No data"? |
| Prometheus lui-même est arrêté | monit status svc_prometheus # Monit mails, Grafana cannot |
| Seuil ou tableau de bord modifié dans l’interface web | # overwritten by the next playbook run - change it in the role |
🔭 La suite
- Journaux et métriques dans une seule vue : Loki est là depuis octobre 2026 ; relier un pic dans un panneau aux lignes de journal de la même minute est l’étape suivante.
- Fait les 20 et 21 octobre 2026 : une alerte sur la file d’attente de PHP-FPM (seuil tiré de 14 jours de mesures), et
/grafanaderrière la même liste de pays que SSH et l’admin WordPress – l’ingress controller répond 403 partout ailleurs. - Les tableaux de bord sous forme de code (Jsonnet/Grafonnet) quand les tableaux maison dépasseront le nombre d’un.
⚖️ Alternatives – et pourquoi Grafana + Prometheus
| Option | Point fort | Pourquoi pas ici |
|---|---|---|
| Netdata | Aucune configuration, résolution à la seconde | Par hôte, historique court par défaut, moins adapté aux métriques Kubernetes. |
| Zabbix / Icinga | Supervision classique par contrôles, alertes éprouvées | Les contrôles disent « en marche ou pas », pas « combien depuis quand » ; les métriques de conteneurs demandent du travail en plus. Icinga a été testé en laboratoire. |
| Services de supervision cloud | Rien à exploiter | Les métriques quittent le serveur ; coûts par hôte et par série. |
| Prometheus + Grafana | Standard pour Kubernetes, modèle pull, ouvert, tableaux de bord pour chaque exporteur | Choisi. |
Un tableau de bord est un ensemble de questions posées par quelqu’un d’autre. Les utiles ici sont celles dont l’état normal est connu – c’est pourquoi cet article indique « normal ici » à côté de chaque panneau. Et une alerte ne vaut que par son dernier test : la ligne la plus importante de cet article est celle sur des règles restées vertes pendant des semaines sans jamais pouvoir se déclencher.


