ArchyntArchynt.api
Retour au blogIngénierie

Pourquoi on n'a pas écrit notre propre capteur eBPF

Beyla résout déjà la partie difficile, ingrate et permanente du traçage au niveau kernel. La reconstruire nous aurait coûté la seule chose qu'on ne peut pas récupérer.

23 juin 2026 · 6 min de lecture

L'agent runtime doit savoir à quelle vitesse un service répond et à quelle fréquence il échoue, sans toucher à l'application. C'est une phrase facile à écrire dans un pitch deck. L'obtenir depuis un processus en production sans SDK, sans sidecar, sans redémarrage, c'est un tout autre problème — et pendant les premières semaines de construction de l'agent, on pensait qu'on allait le résoudre nous-mêmes.

Le plan était simple sur le papier : des uprobes sur SSL_write/SSL_read pour le trafic TLS, des kprobes sur tcp_sendmsg pour le reste, parser le framing HTTP et gRPC dans un petit programme eBPF, produire des métriques RED (rate, errors, duration) sans que le processus cible sache jamais qu'il était observé. On a eu un proof of concept qui tournait contre un serveur HTTP Go basique en moins d'une semaine. Puis on l'a pointé sur un vrai service Spring Boot, et tout s'est écroulé.

Où ça casse vraiment

Pas au niveau du vérificateur eBPF — cette partie-là est en fait bien conçue, et le kernel rejette un programme qui pourrait boucler ou planter bien avant qu'il ne tourne. Ça casse à la frontière userspace, dans la partie que personne ne met dans le talk de conférence : les offsets d'uprobe dépendent exactement de la build de la bibliothèque. L'offset de SSL_write pour OpenSSL 3.0.2 sur Ubuntu 22.04 n'est pas celui d'OpenSSL 3.0.13 sur la même distribution six mois plus tard, et c'est un autre chiffre encore sur une build liée à musl chez Alpine, et encore différent une fois qu'on est dans une JVM qui fait son propre TLS via un provider embarqué plutôt que celui du système. Multipliez ça par chaque runtime de langage, chaque image de base de conteneur, chaque version mineure qu'un client se trouve à exécuter, et vous obtenez une matrice d'offsets qui nécessite une re-dérivation constante et un banc de test pour des kernels que vous ne contrôlez pas.

Rien de tout ça n'est un problème de recherche. C'est un problème de maintenance, pour toujours, et ça ne s'arrête pas une fois qu'on a shippé — chaque version mineure d'OpenSSL est une régression potentielle qu'on découvre via un message Slack d'un client plutôt que par notre propre CI.

Pourquoi on a choisi Beyla à la place

Beyla (le projet d'instrumentation eBPF de Grafana Labs) porte déjà ce fardeau de maintenance, en open source, avec une communauté de gens dont le travail à plein temps consiste à traquer le drift du kernel et des bibliothèques sur exactement les environnements qu'on aurait dû découvrir un client à la fois. Il nous donne des métriques RED par service — taux de requêtes, taux d'erreur, durée p50/p99 — sans une ligne de code dans l'application cible. On peut consacrer notre propre budget eBPF à ce qui est vraiment à nous : procnet, notre propre collecteur qui lit /proc/<pid>/net/tcp pour associer les connexions TCP en direct aux conteneurs — une surface plus étroite et plus stable que de parser des protocoles L7 dans le kernel.

Le coût honnête de cette décision, c'est qu'aujourd'hui l'agent s'expédie en deux conteneurs au lieu d'un — le nôtre, et celui de Beyla, tous deux avec des privilèges élevés sur l'hôte. C'est une friction sur laquelle on travaille activement (empaqueter Beyla comme processus enfant supervisé du binaire de l'agent est la prochaine étape), mais c'est un problème d'UX à résoudre, pas un pari d'ingénierie qu'on doit gagner contre une cible mouvante. On préfère shipper cette friction honnêtement plutôt que de prétendre avoir construit quelque chose qu'on n'a pas construit.

La règle à laquelle on est arrivés

Construisez ce qui est vraiment votre produit. Pour nous, c'est le graphe : la résolution d'entités qui donne au « service orders » la même identité qu'on le voie depuis un Dockerfile, un conteneur en cours d'exécution, ou une connexion TCP, et la logique de corrélation qui décide si une dépendance est réelle. L'eBPF à la frontière de l'ABI kernel, à travers chaque langage et chaque image de base de conteneur qu'un client pourrait exécuter, c'est déjà le travail à plein temps de quelqu'un d'autre — et ils sont bons à ça.

Vous voulez voir ça sur votre propre système ?

L'URL d'un dépôt suffit pour le graphe statique. L'agent runtime ne nécessite qu'un seul fichier docker-compose.