§ Il problema con i container e il monitoraggio tradizionale
Il monitoraggio classico presuppone che le cose abbiano un nome stabile. Hai un host, hai dei servizi, li configuri una volta e dimentichi. Con Docker questo modello si rompe quasi subito.
I container nascono e muoiono. I nomi cambiano tra un deploy e l'altro se non li fissi esplicitamente. Con orchestratori come Swarm o anche semplici compose con scaling, puoi ritrovarti con app_web_1, app_web_2, app_web_3 in un pomeriggio e zero container la mattina dopo.
La prima volta che ho provato a monitorare un ambiente Docker con Zabbix "alla vecchia maniera" — item statici, trigger hardcoded per nome container — ho capito dopo due settimane che stavo monitorando ghost. Container che non esistevano più, alert su servizi rinominati, nessuna visibilità sui nuovi container deployati.
La soluzione è il Low-Level Discovery. Esattamente come per i filesystem o le interfacce di rete, Zabbix può scoprire automaticamente i container in esecuzione e creare item, trigger e grafici per ciascuno.
§ Architettura: agent sull'host, non nel container
Prima decisione: dove gira lo Zabbix Agent? Due approcci comuni:
- Agent sull'host — un singolo agent sul nodo Docker, accede al socket
/var/run/docker.socke vede tutti i container. Meno overhead, meno complessità. - Agent come sidecar — un container Zabbix Agent per ogni stack Docker, con accesso al socket montato come volume. Più isolato, ma moltiplica gli agent da gestire.
In produzione uso l'agent sull'host. È più semplice, funziona con il template ufficiale senza modifiche, e non aggiunge un container al compose solo per monitorare gli altri.
L'unica cosa da verificare: l'utente con cui gira l'agent deve poter leggere il socket Docker.
# Aggiungi l'utente zabbix al gruppo docker
usermod -aG docker zabbix
# Verifica
id zabbix
# uid=109(zabbix) gid=109(zabbix) groups=109(zabbix),998(docker)Se usi SELinux o AppArmor, configura le policy di conseguenza. Non è questo l'articolo per approfondire SELinux, ma non ignorarlo in produzione.
§ Il template ufficiale: Docker by Zabbix Agent 2
Dal 5.4 in poi Zabbix distribuisce un template Docker ufficiale pensato per Zabbix Agent 2, che ha il plugin Docker nativo. Non serve configurare UserParameter o script esterni.
Il template si chiama Docker by Zabbix agent 2 ed è disponibile su zabbix.com/integrations/docker. Se usi Zabbix 6.x o 7.x, è già incluso nei template di default.
Il prerequisito è usare Agent 2 (zabbix-agent2), non il classico zabbix-agent. Su Debian/Ubuntu:
apt install zabbix-agent2
systemctl enable --now zabbix-agent2Configura il plugin Docker in /etc/zabbix/zabbix_agent2.d/plugins.d/docker.conf:
Plugins.Docker.Endpoint=unix:///var/run/docker.sockRiavvia l'agent e verifica che il plugin risponda:
zabbix_agent2 -t docker.infoSe vedi JSON con le info del daemon Docker, sei a posto.
§ Come funziona il LLD per i container
Il template usa una regola di discovery su docker.containers.discovery. Zabbix Agent 2 interroga il socket Docker, riceve la lista dei container (running e stopped, configurabile), e restituisce un JSON con le macro per ogni container:
[
{"{#NAME}": "nginx", "{#ID}": "a3f8...", "{#STATUS}": "running", "{#IMAGE}": "nginx:1.25"},
{"{#NAME}": "postgres", "{#ID}": "b9c1...", "{#STATUS}": "running", "{#IMAGE}": "postgres:16"},
...
]Da queste macro vengono generati automaticamente item per ogni container:
- Stato container (
docker.container.info["{#NAME}",State.Status]) - CPU usage
- Memoria utilizzata e limite
- Network I/O (rx/tx bytes)
- Block I/O
- Numero di processi nel container
- Numero di restart
Il filtro di default include solo i container in stato running. Se vuoi monitorare anche i container fermi (per trigger su "container non parte"), rimuovi il filtro o aggiungine uno personalizzato.
§ Trigger che uso davvero
Il template include trigger di default, ma in produzione li ho affinati nel tempo. Quelli che hanno fatto la differenza:
Container non in esecuzione
last(/host/docker.container.info["{#NAME}",State.Status])<>"running"Trigger WARNING se il container non è running. Combinato con una dipendenza dall'host, evita falsi positivi durante i riavvii pianificati.
Restart loop
change(/host/docker.container.info["{#NAME}",RestartCount])>0
and
last(/host/docker.container.info["{#NAME}",RestartCount])>3Un container che riavvia spesso è un container che sta soffrendo. Questo trigger scatta quando rileva più di 3 restart totali e il contatore è aumentato nell'ultima rilevazione. Il change() evita alert persistenti su un container già in recovery stabile.
Memoria sopra soglia
last(/host/docker.container.stats["{#NAME}",memory_usage])
/ last(/host/docker.container.stats["{#NAME}",memory_limit]) * 100 > 85Utile se hai impostato mem_limit nel compose. Se non hai un limite, memory_limit ritorna la RAM totale del nodo — in quel caso regola la soglia di conseguenza o skippa il trigger per quei container.
§ Configurare i container per essere monitorabili meglio
Un dettaglio che fa differenza: dai sempre un nome esplicito ai container in Docker Compose.
services:
web:
image: nginx:1.25
container_name: myapp-nginx # nome stabile
app:
image: myapp:latest
container_name: myapp-app # nome stabile
db:
image: postgres:16
container_name: myapp-postgresSenza container_name, Docker usa projectname_service_N. Con scaling questo diventa myapp_web_1, myapp_web_2 — ogni nuova istanza crea nuovi item in Zabbix, e le vecchie rimangono come ghost fino al prossimo cleanup. Con nomi fissi, il LLD è deterministico e gli item rimangono stabili.
§ Labels Docker come macro Zabbix
Un trick meno conosciuto: puoi aggiungere label ai container e usarle come filtri nel LLD o come macro nel template.
services:
web:
image: nginx:1.25
labels:
- "monitoring.tier=frontend"
- "monitoring.alert=true"
- "monitoring.team=infra"Il plugin Docker le espone come {#LABEL.*} nella discovery. Puoi usarle come filtri per escludere container di test, o per raggruppare gli alert per team in Zabbix.
§ Metriche che il template standard non copre
Il template ufficiale copre bene CPU, memoria e network. Mancano alcune cose che ho aggiunto con UserParameter specifici:
Health check status
Se i tuoi container hanno un HEALTHCHECK configurato nell'immagine, Docker espone lo stato in State.Health.Status. Puoi monitorarlo così:
UserParameter=docker.container.health[*],docker inspect --format='{{.State.Health.Status}}' $1 2>/dev/null || echo "none"Poi un item con chiave docker.container.health[nginx] e trigger su valore diverso da healthy.
Numero di container per stato
UserParameter=docker.containers.running,docker ps -q --filter status=running | wc -l
UserParameter=docker.containers.stopped,docker ps -q --filter status=exited | wc -lItem aggregati utili per grafici di capacity planning — quanti container attivi sul nodo nel tempo.
§ Pitfalls che ho trovato
Discovery interval troppo basso. Con interval a 1 minuto su ambienti con molti deploy al giorno, Zabbix crea e distrugge item in continuazione. Il graceful period (quanto aspetta prima di rimuovere item di container non più presenti) di default è 30 giorni — troppo lungo. L'ho abbassato a 7 giorni per ambienti dinamici.
Il plugin Docker e le permission sul socket. Su alcuni sistemi il socket ha permessi 660 con gruppo docker, su altri 666. Dopo ogni update del pacchetto Docker verifico che l'utente zabbix sia ancora nel gruppo — gli update a volte ricreano il gruppo con GID diverso.
Container con nomi Unicode o caratteri speciali. Ho visto container con emoji nel nome (sì, davvero) che rompevano il parser del template. Soluzione: filtro LLD con regex ^[a-zA-Z0-9_-]+$ per escluderli.
Zabbix Agent 2 vs Agent classico. Il plugin Docker funziona solo con Agent 2. Se hai ancora Agent classico su qualche nodo, puoi usare UserParameter con docker inspect come fallback, ma perdi la consistenza del template.
§ Vale la pena rispetto ad alternative?
La domanda giusta da farsi è: se hai già Zabbix per il monitoraggio dell'infrastruttura host, aggiungere il monitoraggio Docker ha senso perché ti dà correlazione diretta tra metriche host e metriche container nello stesso sistema. Un picco di CPU sull'host mentre tre container consumano l'80% della loro quota è una storia coerente in un'unica dashboard.
Se parti da zero o hai un ambiente cloud-native con Kubernetes, esistono soluzioni più native (Prometheus+Grafana, Datadog, ecc.). Ma se Zabbix è già il tuo strumento di riferimento per ER network, SNMP, agenti fisici — estenderlo ai container ha un costo marginale basso e ti evita di gestire un secondo stack di monitoraggio.
Come al solito con Zabbix: funziona, scala, non ti fa dormire tranquillo. Ma almeno adesso ti sveglia per le cose giuste.