3. eBPF 核心技术概览:程序类型、BPF 映射、辅助函数、CO-RE 与 BTF
eBPF 并非单一技术,而是一套由程序类型、映射、辅助函数以及加载验证机制构成的完整生态。理解这四大核心组件,是掌握 eBPF 在 HPA 与灰度门禁场景中应用的基础。
3.1 eBPF 程序类型:挂载点决定能力
eBPF 程序必须挂载到内核的特定事件点(kprobe、tracepoint、XDP、cgroup 等)才能执行。不同的程序类型决定了你能捕获什么数据、在哪个网络或系统层级工作。
| 程序类型 | 挂载点 | 典型用途 | HPA/灰度场景价值 |
|---|---|---|---|
| kprobe/kretprobe | 内核函数入口/返回 | 监控系统调用、函数参数 | 捕获容器 CPU 调度、内存分配 |
| tracepoint | 内核静态跟踪点 | 稳定、低开销的指标采集 | 采集 cgroup 统计、网络事件 |
| XDP | 网卡驱动层 | 高速包过滤、负载均衡 | 灰度流量标记、早期丢弃 |
| TC (clsact) | 内核协议栈 | 流量整形、QoS | 灰度流量限速、重定向 |
| cgroup/skb | cgroup 层级 | 容器网络策略 | 按 Pod 粒度控制出站流量 |
| perf_event | PMU/软件事件 | 性能采样、CPU 分析 | 实时热点检测,辅助弹性决策 |
选型建议: 在 HPA 场景中,优先使用 tracepoint 和 cgroup/skb 类型,因为它们接口稳定、对内核版本依赖低;灰度门禁中,XDP 和 TC 是流量标记与过滤的首选。
3.2 BPF 映射:内核态与用户态的数据桥梁
BPF 映射(Map)是 eBPF 程序的核心数据结构,用于在内核态与用户态之间共享状态、统计计数、配置规则。映射类型决定了数据组织方式与并发语义。
| 映射类型 | 键/值 | 特点 | HPA/灰度场景示例 |
|---|---|---|---|
| BPF_MAP_TYPE_HASH | 任意 | 通用哈希表,支持动态增删 | 存储 Pod IP → 灰度标签映射 |
| BPF_MAP_TYPE_ARRAY | 整数索引 | 固定大小,快速随机访问 | 存储 CPU 使用率统计数组 |
| BPF_MAP_TYPE_PERCPU_HASH | 任意 | Per-CPU 哈希,无锁高性能 | 按 CPU 核聚合容器指标 |
| BPF_MAP_TYPE_RINGBUF | 事件流 | 高性能环形缓冲区,替代 perf_event | 实时推送 Pod 弹性事件 |
| BPF_MAP_TYPE_STACK_TRACE | 栈 ID | 存储调用栈,用于 profiling | 诊断 HPA 误触发根因 |
// 示例:定义灰度标签映射(C 伪代码)
struct bpf_map_def SEC("maps") gray_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(u32), // Pod IP (host order)
.value_size = sizeof(struct gray_rule),
.max_entries = 1024,
};
// 用户态更新映射
int key = pod_ip;
struct gray_rule rule = { .canary = 1, .weight = 30 };
bpf_map_update_elem(&gray_map, &key, &rule, BPF_ANY);
3.3 辅助函数:安全的内核能力调用
eBPF 程序不能直接调用内核函数,必须通过辅助函数(Helper) 完成数据读取、映射操作、事件输出等任务。每个程序类型都有允许调用的辅助函数白名单。
- 数据获取类:
bpf_get_current_pid_tgid()、bpf_get_current_cgroup_id()、bpf_skb_load_bytes() - 映射操作类:
bpf_map_lookup_elem()、bpf_map_update_elem()、bpf_map_delete_elem() - 事件输出类:
bpf_perf_event_output()、bpf_ringbuf_output() - 辅助计算类:
bpf_ktime_get_ns()、bpf_get_prandom_u32()
注意: 辅助函数签名在不同内核版本间可能变化。使用 CO-RE 技术后,eBPF 程序会自动重定位辅助函数偏移,无需为每个内核版本重新编译。
3.4 CO-RE 与 BTF:一次编译,到处运行
传统 eBPF 程序需要为每个目标内核版本编译,维护成本极高。CO-RE(Compile Once – Run Everywhere)配合 BTF(BPF Type Format)解决了这一痛点。
核心原理: 编译器在 eBPF 字节码中记录重定位信息(字段偏移、结构体大小),加载器(libbpf)在运行时根据目标内核的 BTF 信息修正这些偏移,实现跨内核兼容。
3.5 BTF:让内核数据结构自描述
BTF(BPF Type Format)是 CO-RE 的基石。它将内核数据结构(struct、union、enum)的布局信息以紧凑的二进制格式嵌入到 eBPF 对象中。加载器通过 BTF 可以精确知道每个字段的偏移量、大小和对齐方式。
// 查看内核 BTF 信息(需安装 bpftool)
# bpftool btf dump file /sys/kernel/btf/vmlinux format c | head -30
// 查看 eBPF 对象中的 BTF 重定位记录
# bpftool prog show --pretty <prog_id>
实战要点: 在 HPA 灰度门禁项目中,我们使用
vmlinux.h 头文件(由 BTF 生成)来引用内核结构体,配合 SEC("tp/...") 宏定义 tracepoint,实现跨内核版本的指标采集。这是课程后续实战章节的基础。
3.6 核心技术关系总结
| 技术组件 | 角色 | 与 HPA 灰度门禁的关系 |
|---|---|---|
| 程序类型 | 定义挂载点与能力边界 | 选择 cgroup/skb 控制 Pod 流量,选择 tracepoint 采集指标 |
| BPF 映射 | 内核态与用户态数据交换 | 存储灰度规则、Pod 指标、弹性策略 |
| 辅助函数 | 安全调用内核功能 | 获取 cgroup ID、输出事件到用户态 |
| CO-RE + BTF | 跨内核版本兼容 | 确保 eBPF 程序在 Kubernetes 集群不同节点内核上一致运行 |