OpenTelemetry 社区把 eBPF 链路采集做成了 OBI(OpenTelemetry eBPF Instrumentation)。K8s 里在每个节点旁路跑一份 DaemonSet,用 eBPF 看本机服务之间的 HTTP 调用,拼成链路推出去;业务 Pod 维持原样。Docker 镜像一般是 otel/ebpf-instrument,项目地址:github.com/open-telemetry/opentelemetry-ebpf-instrumentation。
链路推到哪看?DataBuff 是开源 APM / 可观测平台,在 UI 里看服务、拓扑和调用链。OBI 把采到的链路推到 DataBuff 就行。项目地址:github.com/databufflabs/databuff。
ns
obi · 业务 Pod 不改、不塞探针 · 采集 Pod 用 eBPF 看本机 HTTP → 推到 DataBuff下面按步骤来。还没有 DataBuff 的先做第 1 步;后面改 YAML 时记清楚业务命名空间和上报地址就行。
curl -fsSL https://databuff.ai/databuff/ai-apm-k8s-install.sh | bash kubectl -n databuff get pods
Pod 都 Running,UI 能打开就行。
在各业务节点上分别检查:
uname -r ls /sys/kernel/btf/vmlinux
内核建议 5.8+,且第二条能列出文件。缺 BTF 的节点上,采集 Pod 会起不来或采不到。
镜像用 otel/ebpf-instrument:latest(实测 latest 可用;生产请钉版本)。集群能出网可跳过;离线则先 pull 再传到各节点 load。
下面 YAML 一次 apply,改两处占位符:YOUR_APP_NAMESPACE → 业务命名空间;YOUR_DATABUFF_HOST → ai-apm-ingest.databuff.svc。hostPID / privileged 是为了看见宿主机进程并挂 eBPF。
# 完整 YAML 见 github.com/databufflabs/databuff 文档或文末 OBI 示例 # 关键配置: # discovery.instrument.k8s_namespace: YOUR_APP_NAMESPACE # ebpf.context_propagation: headers # otel_traces_export.endpoint: http://YOUR_DATABUFF_HOST:4318
kubectl apply -f obi.yaml kubectl -n obi get ds,pods -o wide
看输出:DESIRED / READY 等于节点数,每个 pod/obi-* Running。
kubectl -n obi logs -l app=obi --tail=80 | grep -iE "instrumenting|process|error" | head -30
有 instrumenting process 即可。没有就查命名空间占位符和业务是否在跑。
for i in $(seq 1 80); do curl -sS -m 2 "http://业务地址/" >/dev/null || true sleep 0.2 done
打一两分钟,再进 DataBuff 看服务和链路。
打开应用性能 → 服务,搜应用名;再点开拓扑和链路详情。
| 方案 | 更适合 |
|---|---|
| eBPF + DaemonSet(本文) | 不想注入、不想重启;先看 HTTP 调用;多语言混部先铺一层 |
| 语言 Agent(如 javaagent) | Dubbo、慢 SQL、方法栈;内核不够 5.8+/BTF |
短板也要摆出来,别当银弹:
- 不支持 Dubbo。OBI 主要吃 HTTP / gRPC 这类协议边界;Dubbo RPC 目前采不到,要看调用还得上语言 Agent。
- 看不到方法栈、业务自定义 Span——它在节点外侧旁路观测,进不了你的代码细节。
- 采集 Pod 必须 privileged;节点内核建议 5.8+,还要有 BTF。
这次先铺 OBI;Dubbo、方法栈这类缺口,再补 Agent。
它不进业务代码。每个节点上的 DaemonSet 用 eBPF 盯住本机 HTTP,在用户态拼成 Span,再推到 DataBuff。和 javaagent 的差别也在这里:Agent 在进程里插桩;OBI 在节点边上旁路看,多语言一份 DaemonSet 就能铺一层。
靠上下文传递。YAML 已配 context_propagation: headers。业务不改代码;读和写都在节点外侧的 HTTP 报文上:
- ① 读 Header · 看入站 — 请求进节点时扫
Traceparent:,有就挂上游 traceId/spanId,没有就新生成。 - ② 本机关联 — 出站 HTTP 靠线程、socket 等线索对上刚才的入站。
- ③ 写 Header · 写出站 — sockmap
sk_msg在请求行后面挤进本跳Traceparent,下一跳入站再被读到。
HTTPS 改不了 HTTP 头,上游另有 TCP Option 路径;本文开的是 headers,对明文 HTTP 就是上面这套。