ArchyntArchynt.api
Torna al blogIngegneria

Perché non abbiamo scritto il nostro sensore eBPF

Beyla risolve già la parte difficile, noiosa e perpetua del tracing a livello kernel. Ricostruirla ci sarebbe costata l'unica cosa che non possiamo recuperare.

23 giugno 2026 · 6 min di lettura

L'agente runtime deve sapere quanto velocemente risponde un servizio e con quale frequenza fallisce, senza toccare l'applicazione. È una frase facile da scrivere in un pitch deck. Estrarla da un processo vivo senza un SDK, senza un sidecar, senza un riavvio è un problema diverso, e per le prime settimane di costruzione dell'agente abbiamo dato per scontato che l'avremmo risolto da soli.

Il piano era semplice sulla carta: uprobe su SSL_write/SSL_read per il traffico TLS, kprobe su tcp_sendmsg per il resto, parsing del framing HTTP e gRPC in un piccolo programma eBPF, emissione di metriche RED (rate, errors, duration) senza che il processo osservato si accorgesse mai di essere monitorato. Abbiamo avuto una proof of concept funzionante contro un semplice server HTTP in Go nel giro di una settimana. Poi l'abbiamo puntata su un servizio Spring Boot reale ed è crollata.

Dove si rompe davvero

Non nel verifier eBPF — quella parte è genuinamente ben progettata, e il kernel rifiuta un programma che potrebbe entrare in loop o crashare molto prima che venga eseguito. Si rompe al confine dello userspace, nella parte che nessuno racconta al talk della conferenza: gli offset degli uprobe sono una funzione della build esatta della libreria. L'offset di SSL_write per OpenSSL 3.0.2 su Ubuntu 22.04 non è l'offset di OpenSSL 3.0.13 sulla stessa distro sei mesi dopo, ed è un numero ancora diverso nella build linkata con musl di Alpine, e di nuovo diverso quando sei dentro una JVM che fa il suo proprio TLS tramite un provider incluso invece di quello di sistema. Moltiplica questo per ogni runtime di linguaggio, ogni immagine base di container, ogni versione minore che un cliente si trova a eseguire, e ottieni una matrice di offset che richiede una ri-derivazione costante e un banco di prova per kernel che non controlli.

Niente di tutto questo è un problema di ricerca. È un problema di manutenzione, per sempre, e non finisce quando fai il rilascio — ogni release minore di OpenSSL è una potenziale regressione di cui vieni a sapere da un messaggio Slack di un cliente invece che dalla tua CI.

Perché abbiamo scelto Beyla

Beyla (il progetto di instrumentazione eBPF di Grafana Labs) porta già quell'onere di manutenzione, in modo aperto, con una comunità di persone il cui lavoro a tempo pieno è inseguire il drift di kernel e librerie esattamente negli ambienti che noi avremmo altrimenti scoperto un cliente alla volta. Ci dà metriche RED per servizio — request rate, error rate, durata p50/p99 — con zero codice nell'applicazione osservata. Possiamo così spendere il nostro budget eBPF sulla parte che è davvero nostra: procnet, il nostro collector che legge /proc/<pid>/net/tcp per mappare le connessioni TCP live sui container, una superficie più ristretta e più stabile rispetto al parsing dei protocolli L7 nel kernel.

Il costo onesto di questa decisione è che oggi l'agente viene distribuito come due container invece di uno — il nostro, e quello di Beyla, entrambi con privilegi elevati sull'host. È un attrito su cui stiamo lavorando attivamente (impacchettare Beyla come processo figlio supervisionato del binario dell'agente è il prossimo passo), ma è un problema di UX da risolvere, non una scommessa ingegneristica che dobbiamo vincere contro un bersaglio mobile. Preferiamo mostrare quell'attrito con onestà piuttosto che fingere di aver costruito qualcosa che non abbiamo costruito.

La regola con cui siamo rimasti

Costruisci ciò che è davvero il tuo prodotto. Per noi è il grafo: la risoluzione delle entità che dà a "il servizio orders" la stessa identità sia che venga visto da un Dockerfile, da un container in esecuzione, o da una connessione TCP, e la logica di correlazione che decide se una dipendenza è reale. eBPF al confine dell'ABI del kernel, attraverso ogni linguaggio e ogni immagine base di container che un cliente potrebbe eseguire, è già il lavoro a tempo pieno di qualcun altro — e sono bravi in quello.

Vuoi vederlo sul tuo sistema?

Basta l'URL di un repository per il grafo statico. L'agente runtime richiede un solo file docker-compose.