Superviser serveurs, réseau, bases de données et sites web avec Zabbix 7.0 LTS : installation, agent 2, templates, triggers, alertes, SNMP, proxies, API et mise en production.
Les templates officiels couvrent l'essentiel. Mais tôt ou tard, il faut superviser quelque chose qui n'existe dans aucun template : la taille d'une file de messages maison, le nombre de commandes en attente, la date du dernier export. Ce chapitre montre comment collecter une valeur, la transformer, définir quand elle devient un problème, et laisser Zabbix découvrir seul les éléments à superviser.
Un item est défini par sa clé, qui dit quoi mesurer. Les clés de l'agent suivent la forme nom[paramètres] :
| Clé | Ce qu'elle mesure |
|---|---|
system.cpu.util | Utilisation CPU en pourcentage |
vm.memory.size[pavailable] | Mémoire disponible en pourcentage |
vfs.fs.size[/,pused] | Espace utilisé sur la racine, en pourcentage |
net.if.in["eth0"] | Trafic entrant sur une interface, en octets par seconde |
proc.num[nginx] | Nombre de processus nginx |
net.tcp.service[http,,8080] | Le port 8080 répond-il en HTTP (1 ou 0) |
systemd.unit.info[cron.service] | État d'une unité systemd (agent 2) |
log[/var/log/app.log,ERROR] | Nouvelles lignes contenant ERROR (actif uniquement) |
Trois réglages comptent pour chaque item :
Quand aucune clé native ne convient, on en crée une. Un UserParameter associe une clé à une commande shell exécutée par l'agent. On les place dans un fichier à part, pour ne pas toucher à la configuration principale :
UserParameter=app.queue.size,/usr/local/bin/queue-size.sh
UserParameter=app.backup.age,echo $(( $(date +%s) - $(stat -c %Y /backup/last.dump) ))
UserParameter=app.orders.pending[*],psql -At -U monitor -d $1 -c "SELECT count(*) FROM orders WHERE status='pending'"La troisième ligne prend un paramètre : [*] accepte des arguments, récupérés en $1, $2. La clé devient app.orders.pending[shop].
systemctl restart zabbix-agent2
zabbix_agent2 -t app.backup.ageLe script s'exécute avec l'utilisateur zabbix. Vérifiez qu'il a les droits nécessaires, et gardez les commandes rapides : au-delà du délai d'expiration de l'item, trois secondes par défaut, la valeur est perdue. Depuis Zabbix 7.0, ce délai se règle item par item.
Une valeur brute est rarement directement exploitable. Le prétraitement la transforme avant stockage, dans l'onglet Preprocessing de l'item. Les étapes s'enchaînent.
| Étape | Exemple d'usage |
|---|---|
| JSONPath | Extraire $.queue.size d'une réponse d'API |
| Regular expression | Extraire un numéro de version d'un texte |
| Change per second | Transformer un compteur d'octets en débit |
| Custom multiplier | Convertir des kilo-octets en octets |
| Discard unchanged with heartbeat | Ne stocker la valeur que si elle change, ou au moins une fois par heure |
| JavaScript | Tout le reste |
« Discard unchanged with heartbeat » est sous-utilisé. Une version de logiciel, un statut qui vaut « OK » 99 % du temps : inutile de les écrire en base toutes les minutes. Avec un heartbeat d'une heure, on garde une valeur par heure tant que rien ne change, et chaque changement immédiatement.
Un item dépendant ne collecte rien lui-même. Il reçoit la valeur d'un item maître et en extrait une partie par prétraitement. C'est le bon modèle pour une API qui renvoie un JSON complet :
https://api.example.com/health toutes les minutes, avec un historique à 0 pour ne pas stocker le JSON brut.$.database.latency_ms.$.queue.pending.$.version, avec « discard unchanged ».Une seule requête HTTP, trois métriques. Les templates officiels utilisent massivement ce modèle.
Un trigger est une expression logique sur des items. Quand elle devient vraie, Zabbix crée un problème. Depuis Zabbix 5.4, la syntaxe est fonction(/hôte/clé,paramètres) :
last(/web-01/vfs.fs.size[/,pused])>90
avg(/web-01/system.cpu.util,5m)>85
nodata(/web-01/agent.ping,5m)=1
last(/web-01/app.backup.age)>90000Dans un template, on remplace le nom d'hôte par le nom du template, et on lit les seuils dans des macros :
min(/Mon template app/app.queue.size,10m)>{$APP.QUEUE.MAX}| Fonction | Ce qu'elle renvoie | Usage |
|---|---|---|
last | La dernière valeur | États : service arrêté, valeur à 0 |
avg | La moyenne sur une période | Charge, latence |
min | Le minimum sur une période | « Au-dessus du seuil pendant tout ce temps » |
max | Le maximum sur une période | « Le seuil a été atteint au moins une fois » |
nodata | 1 si aucune donnée reçue depuis la durée | Agent muet, script cassé |
change | La différence avec la valeur précédente | Redémarrage, changement de version |
count | Le nombre de valeurs qui respectent une condition | « 3 erreurs sur les 10 derniers checks » |
min(...,10m)>90 est l'arme principale contre les fausses alertes. Le CPU dépasse 90 % pendant vingt secondes à chaque sauvegarde : avec last, une alerte. Avec min sur dix minutes, seulement si la charge reste au-dessus du seuil pendant toute la période.
| Sévérité | Usage recommandé |
|---|---|
| Not classified | À éviter |
| Information | Un événement à noter, aucune action requise |
| Warning | À regarder dans la journée |
| Average | À traiter rapidement, pas d'impact utilisateur encore |
| High | Impact en cours ou imminent |
| Disaster | Service arrêté pour les utilisateurs |
La sévérité pilote ensuite le routage des alertes. Si tout est en « High », plus rien ne l'est.
Un disque qui oscille entre 89 % et 91 % ouvre et ferme un problème toutes les cinq minutes. La solution est une expression de rétablissement distincte : le problème s'ouvre à 90 %, mais ne se ferme qu'en dessous de 85 %.
| Champ | Valeur |
|---|---|
| Problem expression | last(/web-01/vfs.fs.size[/,pused])>90 |
| OK event generation | Recovery expression |
| Recovery expression | last(/web-01/vfs.fs.size[/,pused])<85 |
Quand un switch tombe, les vingt serveurs derrière lui deviennent injoignables. Sans dépendances, vous recevez vingt et une alertes. Avec une dépendance déclarée sur chaque trigger « agent injoignable » vers le trigger « switch injoignable », Zabbix n'alerte que sur le switch : les autres problèmes sont masqués tant que la cause racine est active.
On déclare la dépendance dans l'onglet Dependencies du trigger. Le même mécanisme évite les doublons sur un seul hôte : le trigger « disque à 90 % » (Average) dépend de « disque à 95 % » (High). Quand le disque dépasse 95 %, seul le problème le plus grave reste affiché. Les templates officiels procèdent ainsi.
Un serveur a deux disques, un autre en a sept. Une machine a une interface réseau, une autre en a douze. Écrire un item par disque et par interface est impossible à maintenir. La découverte bas niveau résout ce problème.
Une règle de découverte renvoie une liste d'objets en JSON, avec des macros LLD comme {#FSNAME} ou {#IFNAME}. Zabbix crée ensuite, pour chaque objet découvert, les items, triggers et graphiques définis comme prototypes.
| Règle de découverte | Macro | Prototypes typiques |
|---|---|---|
vfs.fs.discovery | {#FSNAME}, {#FSTYPE} | Espace utilisé, inodes |
net.if.discovery | {#IFNAME} | Trafic entrant, sortant, erreurs |
system.cpu.discovery | {#CPU.NUMBER} | Charge par cœur |
systemd.unit.discovery | {#UNIT.NAME} | État de chaque service |
Le prototype d'item vfs.fs.size[{#FSNAME},pused] devient vfs.fs.size[/,pused], vfs.fs.size[/var,pused], etc. Le prototype de trigger suit le même principe.
Deux réglages évitent les ennuis :
{#FSTYPE} exclut tmpfs et overlay, sinon chaque conteneur Docker crée des systèmes de fichiers à superviser.Une règle de découverte peut aussi être un UserParameter qui renvoie un tableau JSON :
#!/bin/sh
printf '['
first=1
for q in $(ls /var/spool/app/queues); do
[ $first -eq 0 ] && printf ','
printf '{"{#QUEUE}":"%s"}' "$q"
first=0
done
printf ']'UserParameter=app.queue.discovery,/usr/local/bin/discover-queues.sh
UserParameter=app.queue.size[*],ls /var/spool/app/queues/$1 | wc -lLa règle de découverte utilise la clé app.queue.discovery, et le prototype d'item app.queue.size[{#QUEUE}]. Ajoutez une file sur le serveur : elle apparaît dans Zabbix à la découverte suivante, avec son item et son trigger.
Un bon item mesure quelque chose d'utile à la bonne fréquence. Un bon trigger ne se déclenche que quand un humain doit agir. Le second est plus difficile que le premier, et c'est lui qui détermine si votre supervision sera écoutée ou ignorée. Le chapitre suivant transforme ces problèmes en alertes qui arrivent aux bonnes personnes.