基于 eBPF 的云原生网络可观测性实战

2026-06-03 22:02 基于 eBPF 的云原生网络可观测性实战已关闭评论

基于 eBPF云原生网络可观测性实战:从零搭建到生产级排障

结论先行: eBPF 让云原生网络可观测性从“黑盒猜测”变成了“内核级透视”,但落地时有三个坑你必须提前知道:内核版本、权限模型、以及数据风暴。

为什么放弃传统方案?

过去排查 K8s 网络问题,我的流程是:kubectl exec 进 Pod → tcpdump → 抓包 → 本地分析。痛点很明显:

  • 每个节点都要装 Agent,资源开销大
  • 无法追踪跨节点、跨 Service Mesh 的请求链路
  • 容器重启后,旧数据丢失

eBPF 方案直接在内核层挂载钩子,对应用零侵入,且能拿到完整上下文。我选择了 Cilium 作为载体(它内置了 Hubble 可观测性组件),因为社区最活跃,文档最全。

第一步:环境准备(踩坑实录)

我的环境: 3 节点 K8s 集群(1 Master + 2 Worker),Ubuntu 22.04,内核 5.15。

注意: eBPF 需要内核 >= 4.19,且开启 CONFIG_DEBUG_INFO_BTF。5.10+ 内核最省心。

踩坑 1:内核版本检测

uname -r
# 5.15.0-86-generic

如果你的内核低于 4.19,必须升级。我试过在 4.15 内核上强装 Cilium,结果 eBPF 程序加载失败,报 invalid argument

踩坑 2:权限问题

eBPF 需要 CAP_BPF 或 root 权限。在 Docker 容器中运行 Cilium Agent 时,必须挂载 /sys/fs/bpf/sys/kernel/debug

# cilium-agent DaemonSet 的关键配置
securityContext:
  capabilities:
    add:
      - SYS_ADMIN
      - NET_ADMIN
      - SYS_RESOURCE
volumeMounts:
  - name: bpf-maps
    mountPath: /sys/fs/bpf
    mountPropagation: Bidirectional

如果你用 Helm 安装,默认已经处理了,但自建集群时容易漏。

第二步:安装 Cilium + Hubble

我直接用 Helm 安装,指定 eBPF 模式:

helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium \
  --namespace kube-system \
  --set bpf.masquerade=true \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true

安装完检查状态:

kubectl -n kube-system get pods -l k8s-app=cilium
# 全部 Running 后,验证 eBPF 是否生效
cilium status | grep "BPF"
# BPF:          OK

关键验证命令: cilium status 会显示 BPFKubernetes 状态,如果出现 Disabled,大概率是内核或权限问题。

第三步:开启网络流量追踪

Hubble 默认只采集部分指标,要看到完整流量,需要开启 monitor-aggregation

kubectl -n kube-system edit configmap cilium-config
# 添加或修改:
monitor-aggregation: none  # 关闭聚合,捕获所有包

注意: 生产环境建议用 mediumlow,否则流量大的集群会写爆 BPF Map。

然后启动 Hubble UI:

cilium hubble enable
cilium hubble port-forward
# 访问 http://localhost:12000

第四步:实战排障——Pod 间通信延迟

场景

一个微服务 order-svc 调用 payment-svc,偶尔出现 3-5 秒延迟。传统 kubectl logstcpdump 都抓不到规律。

用 eBPF 抓现场

  1. 找到 Pod 的 IP
kubectl get pod -l app=order-svc -o wide
# IP: 10.1.0.15
  1. 在 Hubble UI 中过滤
    输入 source=10.1.0.15,看到目标 IP 10.1.0.22(payment-svc)。

  2. 用 CLI 追踪具体连接

hubble observe --from-pod default/order-svc-xxx --to-pod default/payment-svc-yyy --verdict DROPPED

输出显示大量 TCP RST 包,且重传率达到 15%。

  1. 深入内核级指标
cilium bpf metrics list | grep "drop"
# drop_count: 142
# reason: CT_MAP_INSERT_FAILED

真相浮出水面: Cilium 的连接跟踪表(CT Map)满了,导致新连接被丢弃,触发 TCP 重传和延迟。

解决方案

增大 CT Map 大小:

helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --set bpf.ctMapEntriesMax=524288  # 默认 65536

调整后延迟从 3s 降到 50ms。

第五步:高级技巧——自定义 eBPF 指标

Cilium 内置了丰富的 Prometheus 指标,但有时你需要自定义。我写了一个简单的 eBPF 程序来统计特定 Service 的 RTT:

// rtt_tracker.c (简化版)
#include <bpf/bpf_helpers.h>

struct rtt_key {
    __u32 src_ip;
    __u32 dst_ip;
};

struct rtt_value {
    __u64 total_rtt_ns;
    __u64 count;
};

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, struct rtt_key);
    __type(value, struct rtt_value);
} rtt_map SEC(".maps");

SEC("kprobe/tcp_rcv_established")
int trace_rtt(struct pt_regs *ctx) {
    // 从 skb 中提取 src/dst IP
    // 计算 RTT 并更新 map
    return 0;
}

然后通过 Cilium 的 bpf-lb 模式加载,暴露为 Prometheus 指标。
不要害怕写 eBPF 代码——对于 1-3 年经验的开发者,从复制社区代码开始,改几行即可。

踩坑总结(诚实记录)

原因 解决
eBPF 程序加载失败 内核版本低 升级到 5.10+
Hubble 看不到流量 monitor-aggregation 默认 high 改为 none 或 medium
节点重启后 BPF Map 丢失 未挂载持久化卷 在 DaemonSet 中配置 hostPath
流量大时 CPU 飙升 eBPF 钩子过多 减少 tracepoint,改用 kprobe

延伸思考:下一步怎么玩?

  • 集成到 Grafana:Cilium 暴露了 cilium_bpf_map_pressurecilium_drop_count 等指标,配合 Loki 日志可以构建全链路可观测性。
  • 服务网格场景:eBPF 可以替代 Envoy 做 Sidecar 流量拦截,性能提升 40%+(参考 Cilium Service Mesh)。
  • 安全审计:用 eBPF 监控 connect() 系统调用,实时检测异常外连——这是云原生安全的起点。

最后说一句:eBPF 不是银弹,它解决的是“内核级数据获取”问题,但数据分析、告警、可视化依然需要传统工具配合。先跑通 Hubble,再上自定义程序,最后才考虑写 eBPF 代码——这个顺序能让你少踩 80% 的坑。

你可能感兴趣的文章

来源:每日教程每日一例,深入学习实用技术教程,关注公众号TeachCourse
转载请注明出处: https://teachcourse.cn/4207.html ,谢谢支持!

资源分享

分类:DevOps 标签:, , , ,
sql server存储过程基础语法 sql server存储过程基础语法
Claude Code 如何写 Skill 技能 Claude Code 如何写 Skill 技
基于 eBPF 的云原生网络可观测性实战 基于 eBPF 的云原生网络可观测
面向抽象的编程思想之重写RecyclerView 面向抽象的编程思想之重写Recyc

评论已关闭!