ADR-0013 - Observability stack: Prometheus + Grafana + Loki + Alertmanager self-hosted
- Status: Accepted (2026-05-15)
- Deciders: Massimo Bagnoli (architect), Claude (sintesi Architect+DevOps+QA+FinOps)
- Implementation tasks: TASK-39 (Prometheus + node_exporter), TASK-40 (FastAPI /metrics), TASK-41 (Grafana + Caddy), TASK-42 (Loki + Promtail), TASK-43 (Alertmanager + alert rules)
- Supersedes: nessuno
- Superseded by: nessuno
Context
Akira e' una piattaforma VoIP wholesale Class-4 con stack distribuito: FastAPI, Kamailio, RTPengine, FreeSWITCH, Postgres/TimescaleDB, Redis e NATS. Senza observability centrale, ogni incidente operativo diventa una sessione manuale di SSH, journalctl e tail su host diversi, con tempi di diagnosi alti e rischio di perdere segnali correlati.
I task TASK-39, TASK-40, TASK-41, TASK-42 e TASK-43 introducono lo stack observability. Questa ADR rende esplicite le motivazioni della scelta, i trade-off rispetto a servizi managed e stack alternativi, le policy di retention e la proiezione costi a 12 mesi.
Vincoli operativi:
- Budget: sotto 20 EUR/mese per staging e sotto 100 EUR/mese per produzione per la sola observability infrastructure.
- Skillset team: 1 developer principale piu' agenti AI, senza ops dedicato.
- Privacy: log e metriche possono contenere numeri telefonici, tenant id o altri dati operativi sensibili.
- Onboarding: un nuovo dev deve usare dashboard base e alert senza conoscere PromQL o LogQL avanzati.
- Scope Fase 1: 3 server staging.
- Scope Fase 2: circa 12 server totali.
- Scope produzione Fase 4: circa 15-20 server con target iniziale 200 CPS.
Decision
Adottiamo uno stack Grafana Labs self-hosted basato su componenti open-source installati come servizi di sistema e gestiti via Ansible.
| Componente | Versione target | Ruolo | Bind | Reverse proxy |
|---|---|---|---|---|
| Prometheus | 2.55.x | Metrics scrape e storage TSDB | 127.0.0.1:9090 | via Caddy solo se necessario |
| node_exporter | 1.8.x | Metriche OS su ogni host | :9100 su rete privata/Tailscale | nessuno |
| FastAPI Instrumentator | 7.x | Metriche applicative /metrics | processo API | nessuno |
| Grafana | 11.3.x | UI, dashboard e datasource | 127.0.0.1:3001 | Caddy grafana.akira-staging.asheep.it |
| Loki | 3.2.x | Aggregazione log | 127.0.0.1:3100 | via datasource Grafana |
| Promtail | 3.2.x | Log shipper su ogni host | :9080 locale/privato | nessuno |
| Alertmanager | 0.27.x | Routing alert e silenziamenti | 127.0.0.1:9093 | Caddy alerts.akira-staging.asheep.it |
Retention policies
- Prometheus metrics: retention 30 giorni, limite locale 20GB.
- Loki logs staging: retention 30 giorni, stima 50MB/giorno per 3 host, circa 1.5GB/mese.
- Loki logs produzione: retention 30 giorni, stima 500MB/giorno per 15 host a 200 CPS, circa 15GB/mese.
- Alertmanager state: effimero, in memoria, senza persistenza richiesta in Fase 1.
La retention di 30 giorni e' sufficiente per troubleshooting operativo, review settimanali degli SLO e confronto con deploy recenti. Non copre esigenze di audit a 12 mesi: quel requisito richiedera' export separato o storage freddo.
Network topology
- Prometheus, Grafana, Loki e Alertmanager fanno bind su localhost sul nodo management.
- node_exporter e promtail sono raggiungibili solo da rete privata o Tailscale; il firewall Hetzner blocca l'accesso pubblico.
- Caddy e' l'unico entry point HTTP pubblico per le UI autorizzate.
- Lo scrape Prometheus usa hostname stabili, preferibilmente Magic DNS Tailscale o inventory Ansible, evitando IP hardcoded.
Auth
- Grafana: password admin da vault (
vault_grafana_admin_password), anonymous disabilitato, sign-up disabilitato. - Prometheus: nessuna auth applicativa in Fase 1; il controllo e' dato dal bind localhost e dalla mancata esposizione via Caddy.
- Loki:
auth_enabled: false, accessibile solo dal datasource Grafana su localhost. - Alertmanager: UI esposta via Caddy; basic auth o altro controllo di accesso potra' essere aggiunto in un task successivo.
Alert routing
- Critical: Telegram bot verso canale NOC, repeat ogni 1h.
- Warning: email a
noc@asheep.it, repeat ogni 4h. - Info: solo dashboard in Fase 1, senza notifica attiva.
- Inhibition:
HostDownsilenzia altri alert dello stesso host per ridurre rumore operativo.
Cost projection 12 months
In Fase 1 lo stack gira su akira-mgmt-01-staging, gia' previsto per altri servizi management. Il costo incrementale e' quindi vicino a 0 EUR/mese, salvo storage extra.
| Scenario | Host | Storage stimato | Costo licenza | Costo infra incrementale | Proiezione 12 mesi |
|---|---|---|---|---|---|
| Staging Fase 1 | 3 | circa 20GB metriche + 2GB log/mese hot | 0 EUR | 0-5 EUR/mese | 0-60 EUR |
| Fase 2 | 12 | circa 20GB metriche + 8-10GB log/mese hot | 0 EUR | 5-15 EUR/mese | 60-180 EUR |
| Produzione Fase 4 | 15-20 | circa 20GB metriche + 15-25GB log/mese hot | 0 EUR | 15-50 EUR/mese | 180-600 EUR |
Il costo resta sotto il budget indicato finche' la retention hot rimane a 30 giorni. Se viene richiesto un anno di log interrogabili in Loki, servono storage volume dedicato o tiering; a 15GB/mese la sola retention annuale dei log vale circa 180GB piu' overhead.
Consequences
Positive
- Costo licenza nullo: Prometheus, Grafana OSS, Loki, Promtail, node_exporter e Alertmanager non introducono fee SaaS.
- Costo incrementale basso: Fase 1 usa capacity gia' disponibile sul nodo management.
- Privacy first: metriche e log restano dentro l'infrastruttura Akira.
- Stack coerente: PromQL, LogQL e dashboard vivono nella stessa UI, riducendo il numero di strumenti da imparare.
- Debug generalist-friendly: componenti single-purpose, config YAML e systemd sono piu' ispezionabili di una piattaforma SaaS opaca.
- Tailscale-native: scrape e shipping possono restare su rete privata senza aprire porte pubbliche.
- Migrazione futura chiara: Grafana Cloud puo' essere introdotto cambiando remote write/datasource senza riscrivere metriche e dashboard di base.
Negative
- Single point of failure: in Fase 1 tutto converge su
mgmt-01; se cade, si perdono metriche, log e alerting. - Bootstrap alerting debole: Alertmanager sullo stesso nodo che deve monitorare non puo' notificare la propria indisponibilita' totale.
- Storage da monitorare: Loki in produzione puo' crescere rapidamente; 30 giorni sono gestibili, 12 mesi hot no.
- No tracing distribuito: Tempo, Jaeger e OpenTelemetry non sono inclusi in questa ADR.
- Rule maintenance manuale: alert rules in YAML versionate in Git sono auditabili, ma meno comode di una UX managed.
- Dipendenza Telegram: le notifiche critical dipendono da un servizio terzo; l'email resta canale secondario ma non sostituisce SMS o paging dedicato.
Neutral
- La scelta self-hosted e' una decisione di Fase 1/Fase 2, non un rifiuto permanente del managed.
- Loki privilegia costo e integrazione con Grafana rispetto alla potenza di ricerca full-text di Elasticsearch.
- Retention hot di 30 giorni e retention audit a lungo termine sono problemi distinti e vanno trattati con policy separate.
Alternatives considered
A1 - Grafana Cloud
Grafana Cloud offre Prometheus-compatible metrics, Loki-compatible logs, dashboard managed e alerting gestito.
Pro: riduce operations, include piani free/entry-level e mantiene compatibilita' concettuale con lo stack scelto.
Contro: costo crescente con serie metriche, log e utenti; invio di dati sensibili a terza parte; dipendenza da policy e limiti del provider.
Verdict: rejected per Fase 1. Possibile upgrade in Fase 4 se l'onere operativo del self-hosted supera il costo managed.
A2 - DataDog
DataDog e' una piattaforma SaaS completa per metriche, log, APM, synthetics e alerting.
Pro: UX molto matura, integrazioni ampie, alerting potente e bassa manutenzione interna.
Contro: costo fuori budget per 15-20 host con log/APM, lock-in forte e minore controllo sui dati sensibili.
Verdict: rejected categoricamente per budget e privacy.
A3 - ELK stack
Elasticsearch, Logstash e Kibana sono uno stack maturo per log search e analytics.
Pro: ricerca full-text potente, ecosistema grande, adatto a use case log-centric complessi.
Contro: richiede piu' RAM e tuning, non copre metriche native, introduce complessita' operativa sproporzionata per Fase 1.
Verdict: rejected. Loki e' sufficiente per log operativi correlati a metriche e dashboard Grafana.
A4 - CloudWatch
CloudWatch sarebbe l'opzione managed naturale in un'infrastruttura AWS.
Pro: integrato con AWS, metriche e log gestiti, alerting disponibile.
Contro: Akira gira su Hetzner, quindi introdurrebbe una dipendenza cloud non necessaria, trasferimento dati e lock-in senza beneficio proporzionato.
Verdict: rejected come non applicabile all'architettura corrente.
A5 - Prometheus + InfluxDB + Telegraf
InfluxDB e Telegraf possono coprire metriche time-series e collection multi-source.
Pro: InfluxDB e' valido per long-term time-series e Telegraf ha molti input plugin.
Contro: duplica il ruolo di Prometheus, aggiunge un secondo modello query/storage e non risolve i log.
Verdict: rejected per over-engineering e sovrapposizione funzionale.
Implementation references
- TASK-39:
infra/roles/prometheus/,infra/roles/node_exporter/,infra/playbooks/bootstrap_all.yml,infra/playbooks/deploy_management.yml. - TASK-40:
apps/api/src/akira_api/main.pyo equivalente backend FastAPI, Instrumentator e test/metrics. - TASK-41:
infra/roles/grafana/, dashboardfastapi-overviewesystem-overview,infra/roles/caddy/templates/Caddyfile.j2. - TASK-42:
infra/roles/loki/,infra/roles/promtail/, datasource Loki in Grafana. - TASK-43:
infra/roles/alertmanager/, rule Prometheusakira-base.yml, Caddy blockalerts.*.
Monitoring & success metrics
- Prometheus uptime: target 99.5% in Fase 1.
- Loki ingestion lag: p95 sotto 10 secondi dalla generazione del log alla visibilita' in Grafana.
- Alert false positive rate: sotto 5%; alert non actionable vanno rimossi o trasformati in dashboard.
- Dashboard load time: sotto 2 secondi per FastAPI Overview e System Overview su intervallo standard.
- Onboarding nuovo dev: sotto 1 giorno per leggere dashboard base e collegare alert ai runbook.
- Storage usage: alert sopra 85% del volume dedicato a metriche/log.
Open questions
- Multi-tenant Grafana in Fase 4: capire se clienti wholesale dovranno vedere metriche isolate per tenant. Grafana OSS non risolve bene questo caso senza separazioni forti.
- Tracing distribuito: valutare Tempo o Jaeger con OpenTelemetry quando il signaling stack sara' completo.
- High availability observability: decidere in Fase 4 se introdurre Alertmanager cluster, Prometheus federation o servizio esterno di health check.
- Log retention long-term: se audit/compliance richiede 12 mesi, introdurre tier freddo su Storage Box o object storage con export compresso.
- Paging critical: valutare SMS o provider paging dedicato se Telegram/email non sono sufficienti per produzione.