Voici le résumé pour les impatients :
- eBPF vous permet d'exécuter des programmes isolés dans le noyau Linux
- Il offre une compréhension approfondie du comportement des systèmes et des applications
- Sa faible surcharge signifie que vous pouvez l'utiliser en production sans souci
- Il est polyvalent : de l'analyse réseau à la surveillance de la sécurité, eBPF est là pour vous
eBPF 101 : Les Bases
Avant de plonger dans les détails, voyons comment fonctionne eBPF. Imaginez-le comme de petits espions efficaces plantés dans votre noyau Linux. Ces espions (programmes eBPF) peuvent rapporter tout, des appels système aux paquets réseau, sans avoir besoin de modifier votre noyau ou de redémarrer votre système.
Voici le tour de magie :
- Vous écrivez un programme eBPF (généralement en C)
- Ce programme est compilé en bytecode eBPF
- Le bytecode est vérifié pour la sécurité (pas de panique du noyau, merci bien)
- Il est ensuite compilé à la volée et injecté dans le noyau
- Votre programme s'exécute lorsque des événements spécifiques se produisent, collectant des données ou modifiant le comportement
C'est comme avoir une équipe de ninjas microscopiques hautement entraînés prêts à rapporter n'importe quel aspect de votre système à tout moment.
Installation de votre Laboratoire eBPF
Prêt à mettre la main à la pâte ? Installons un terrain de jeu eBPF. Tout d'abord, vous aurez besoin d'un noyau Linux relativement récent (4.4+, mais plus récent c'est mieux). Ensuite, installons quelques outils :
sudo apt-get update
sudo apt-get install -y bpfcc-tools linux-headers-$(uname -r)
Cela installe BCC (BPF Compiler Collection), qui nous offre une belle interface Python pour travailler avec eBPF. Maintenant, écrivons notre premier programme eBPF :
from bcc import BPF
# Définir le programme eBPF
prog = """
int hello(void *ctx) {
bpf_trace_printk("Hello, eBPF World!\\n");
return 0;
}
"""
# Charger le programme eBPF
b = BPF(text=prog)
# L'attacher à une fonction du noyau
b.attach_kprobe(event="sys_clone", fn_name="hello")
# Imprimer le résultat
print("Programme eBPF chargé. Suivi de sys_clone()... Ctrl+C pour quitter.")
b.trace_print()
Enregistrez ceci sous hello_ebpf.py
et exécutez-le avec sudo python3 hello_ebpf.py
. Félicitations ! Vous venez de créer un programme eBPF qui dit bonjour chaque fois qu'un nouveau processus est créé.
Surveillance des Processus : Qui Mange Mon CPU ?
Maintenant que nous avons fait un premier pas, allons plus loin. Un cas d'utilisation courant pour eBPF est la surveillance du comportement des processus. Créons un programme qui suit l'utilisation du CPU par processus :
from bcc import BPF
from time import sleep
# Programme eBPF
prog = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
struct key_t {
u32 pid;
u64 cpu;
};
BPF_HASH(stats, struct key_t);
int on_switch(struct pt_regs *ctx, struct task_struct *prev) {
struct key_t key = {};
u64 delta, *time;
key.pid = prev->pid;
key.cpu = bpf_get_smp_processor_id();
time = stats.lookup(&key);
if (time) {
delta = bpf_ktime_get_ns() - *time;
stats.increment(key, delta);
}
key.pid = bpf_get_current_pid_tgid() >> 32;
stats.update(&key, &bpf_ktime_get_ns());
return 0;
}
"""
b = BPF(text=prog)
b.attach_kprobe(event="finish_task_switch", fn_name="on_switch")
print("Surveillance de l'utilisation du CPU... Ctrl+C pour quitter")
while True:
sleep(1)
print("\nTop 5 des processus gourmands en CPU :")
b["stats"].print_log2_hist("Utilisation CPU", "pid", section_print_fn=lambda k, v: f"PID {k.pid:<6} CPU {k.cpu:<3}")
Ce script s'attache à la fonction finish_task_switch
, nous permettant de suivre combien de temps chaque processus passe sur le CPU. Exécutez-le et regardez quels processus accaparent vos précieux cycles CPU !
Analyse Réseau avec eBPF
eBPF n'est pas seulement pour la surveillance des processus ; c'est aussi un outil puissant pour l'analyse réseau. Créons un programme simple pour suivre les connexions réseau :
from bcc import BPF
# Programme eBPF
prog = """
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
BPF_HASH(ipv4_sends, u32, u64);
int trace_ip_send(struct pt_regs *ctx, struct sock *sk) {
u32 dst = sk->__sk_common.skc_daddr;
ipv4_sends.increment(dst);
return 0;
}
"""
b = BPF(text=prog)
b.attach_kprobe(event="ip_send_skb", fn_name="trace_ip_send")
print("Suivi des envois IP... Ctrl+C pour quitter")
try:
while True:
b.perf_buffer_poll()
except KeyboardInterrupt:
print("\nPrincipales destinations IP :")
b["ipv4_sends"].print_log2_hist("Paquets", "IP")
Ce script suit les connexions IPv4 sortantes, vous offrant une vue d'ensemble des destinations de vos paquets. C'est comme avoir votre propre mini Wireshark intégré au noyau !
Intégration de eBPF avec Prometheus et Grafana
Maintenant que nous collectons toutes ces données intéressantes, visualisons-les ! Nous utiliserons Prometheus pour extraire nos métriques eBPF et Grafana pour créer de beaux tableaux de bord.
Tout d'abord, modifions notre script de surveillance du CPU pour exposer des métriques pour Prometheus :
from bcc import BPF
from prometheus_client import start_http_server, Gauge
import time
# ... (code précédent du programme eBPF ici)
# Métriques Prometheus
PROCESS_CPU_USAGE = Gauge('process_cpu_usage', 'Utilisation du CPU par processus', ['pid', 'cpu'])
def update_metrics():
for k, v in b["stats"].items():
PROCESS_CPU_USAGE.labels(pid=k.pid, cpu=k.cpu).set(v.value)
if __name__ == '__main__':
b = BPF(text=prog)
b.attach_kprobe(event="finish_task_switch", fn_name="on_switch")
# Démarrer le serveur HTTP Prometheus
start_http_server(8000)
print("Surveillance de l'utilisation du CPU... Métriques disponibles sur :8000")
while True:
time.sleep(1)
update_metrics()
Configurez maintenant Prometheus pour extraire ces métriques et mettez en place un tableau de bord Grafana pour les visualiser. Vous aurez une vue en temps réel de l'utilisation du CPU de votre système qui ferait saliver n'importe quel administrateur système !
Surveillance de la Sécurité : Attraper les Mauvais Garçons
eBPF n'est pas seulement une question de performance ; c'est aussi un outil puissant pour la surveillance de la sécurité. Créons un système simple de détection d'intrusion qui surveille les accès aux fichiers suspects :
from bcc import BPF
prog = """
#include <uapi/linux/ptrace.h>
#include <linux/fs.h>
BPF_HASH(suspicious_accesses, u32);
int trace_open(struct pt_regs *ctx, const char __user *filename, int flags) {
char fname[256];
bpf_probe_read_user_str(fname, sizeof(fname), (void *)filename);
if (strstr(fname, "/etc/shadow") != NULL) {
u32 pid = bpf_get_current_pid_tgid() >> 32;
suspicious_accesses.increment(pid);
}
return 0;
}
"""
b = BPF(text=prog)
b.attach_kprobe(event="do_sys_open", fn_name="trace_open")
print("Surveillance des accès aux fichiers suspects... Ctrl+C pour quitter")
try:
while True:
b.perf_buffer_poll()
except KeyboardInterrupt:
print("\nAccès suspects détectés :")
b["suspicious_accesses"].print_log2_hist("Tentatives", "PID")
Ce script surveille les tentatives d'accès au fichier /etc/shadow
, ce qui pourrait indiquer que quelqu'un essaie de voler des hachages de mots de passe. C'est un exemple simple, mais il montre comment eBPF peut être utilisé pour la surveillance de la sécurité en temps réel.
Optimisation des Performances : Tirer le Meilleur Parti
Utilisons eBPF pour identifier et optimiser les opérations d'E/S disque lentes :
from bcc import BPF
import time
prog = """
#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>
BPF_HISTOGRAM(dist);
int trace_req_start(struct pt_regs *ctx, struct request *req) {
u64 ts = bpf_ktime_get_ns();
bpf_map_update_elem(&start, &req, &ts, BPF_ANY);
return 0;
}
int trace_req_completion(struct pt_regs *ctx, struct request *req) {
u64 *tsp, delta;
tsp = bpf_map_lookup_elem(&start, &req);
if (tsp != 0) {
delta = bpf_ktime_get_ns() - *tsp;
dist.increment(bpf_log2l(delta / 1000));
bpf_map_delete_elem(&start, &req);
}
return 0;
}
"""
b = BPF(text=prog)
b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
b.attach_kprobe(event="blk_account_io_completion", fn_name="trace_req_completion")
print("Suivi des E/S des périphériques de bloc... Appuyez sur Ctrl+C pour terminer.")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\nHistogramme de latence des E/S de bloc :")
b["dist"].print_log2_hist("usecs")
Ce script mesure la latence des opérations d'E/S disque, vous aidant à identifier les goulets d'étranglement potentiels dans votre système de stockage. Armé de ces informations, vous pouvez prendre des décisions éclairées sur l'optimisation de votre disposition de disque ou la mise à niveau de votre matériel.
Outils eBPF : Vos Nouveaux Meilleurs Amis
Nous n'avons fait qu'effleurer la surface de ce qui est possible avec eBPF. Voici quelques outils puissants que vous devriez connaître :
- bpftrace : Un langage de traçage de haut niveau pour eBPF
- bcc : La BPF Compiler Collection, que nous avons utilisée dans nos exemples
- cilium : Sécurité et visibilité réseau utilisant eBPF
- falco : Surveillance de la sécurité en temps réel alimentée par eBPF
- pixie : Auto-instrumentation et surveillance pour Kubernetes
Chacun de ces outils exploite eBPF de manière unique, offrant des capacités puissantes pour la surveillance, la sécurité et l'optimisation des performances.
Conclusion : La Révolution eBPF
eBPF révolutionne la façon dont nous surveillons et optimisons les systèmes Linux. Il nous offre une visibilité sans précédent sur le comportement du système avec une surcharge minimale, nous permettant de déboguer, sécuriser et optimiser nos systèmes de manière auparavant impossible ou impraticable.
Comme nous l'avons vu, eBPF peut être utilisé pour :
- Introspection profonde du système
- Surveillance et optimisation des performances
- Analyse réseau et sécurité
- Solutions de surveillance personnalisées
Le meilleur dans tout ça ? Ce n'est que le début. À mesure que eBPF continue d'évoluer, nous pouvons nous attendre à voir émerger des outils et techniques encore plus puissants.
Alors, la prochaine fois que vous vous retrouverez face à un problème de performance mystérieux ou que vous vous gratterez la tête devant un bug insaisissable, souvenez-vous : eBPF est votre arme secrète. Bonne surveillance, et que vos systèmes fonctionnent toujours sans accroc !
"Avec un grand pouvoir vient une grande responsabilité." Bien que eBPF vous donne des super-pouvoirs, n'oubliez pas de les utiliser à bon escient. Testez toujours vos programmes eBPF de manière approfondie et soyez conscient de leur impact sur les performances du système.
Maintenant, allez de l'avant et conquérez ces systèmes Linux avec vos nouvelles compétences eBPF !