集群里出现来源不明的网络流量时,eBPF 的价值在于能在内核里直接观察连接建立和数据包处理结果,不用改应用也不用重启负载。排查思路分两条。一条从进程出发,看谁发起了连接,适合定位节点上的异常外联。另一条从集群出发,看哪个工作负载在连接谁、策略判定是什么。前者用 bpftrace 就够,后者用 Cilium 的 Hubble 更省事。
先判断该用哪条路线
选错工具会浪费时间,先用几个问题定路线。
- 已部署 Cilium 并启用 Hubble,优先走集群视角,能直接看到连接与策略判定。
- 只想看节点上哪些进程在往外连,走 bpftrace,不用装额外组件。
- 要看数据包在内核协议栈里的走向,用 tc 挂载点的 BPF 程序。
- 要在多个内核版本上分发同一个工具,选支持 CO-RE 的方案。
用 bpftrace 抓进程发起的连接
这一步要拿到时间、进程号、进程名和地址端口的对应关系。内核函数 tcp_connect 的入参是套接字结构体,从中能读出地址族与目的地址端口。
- 确认节点装了 bpftrace 与匹配内核的调试信息,否则 kprobe 挂不上。
- 编写追踪脚本,在
kprobe:tcp_connect上挂探针,从参数取出套接字指针。 - 读地址族字段判断是否属于 IPv4 或 IPv6,只处理这两类。
- 按地址族分别取目的与源地址,IPv6 按对应字段读。
- 取目的端口后做字节序转换,内核存的端口是大端,不翻转会打出错误数值,这一步最容易出错。
- 在探针里打印时间、进程号、进程名与地址端口。
这种方式记录的是连接尝试,失败或超时的连接同样会出现。开销通常可忽略,它只在建立连接时触发一次。
用 Hubble 看工作负载之间的流量
有 Cilium 的集群上,这一步能省掉写脚本的成本。
- 运行
cilium status确认 Cilium 与 Hubble 正常,再运行hubble status确认能访问观测接口。 - 用
hubble observe按发起方过滤,把范围收到可疑工作负载上。 - 加
--namespace与--pod之类的条件进一步缩小范围,要看应用层再加--protocol http。 - 只看被拒绝的连接就加
--verdict DROPPED,这对判断策略是否误拦很直接。 - 区分方向用
--reply与--not-reply,确认主动外联还是响应流量。 - 确认有没有加密,用
--encrypted与--unencrypted分开看,未加密的外联更要关注。
过滤器还支持按标签、服务、端口、身份和 DNS 名称选择,输出带上发起方、接收方、协议与判定结果,定位异常连接几步就能收敛。
排查结果怎么判读
判读时容易走弯路的地方有几处。
- 只看到内网地址之间的流量,先确认是不是服务网格或采集组件自身产生的,这类组件会有大量外观异常但正常的连接。
- 出现集群外的目的地址,把判定结果与进程名对上,确认是业务外联还是依赖库的遥测上报。
- DNS 解析异常多,单独看解析类流量,有些程序会绕过系统解析器自己构造查询。
- 端口号明显不对,先检查有没有做字节序转换。
- 时间窗口对不上,Hubble 输出是拉取式的,用
--since限定范围再和告警时间靠近。
限制和需要注意的地方
eBPF 的追踪能力受内核版本影响,探针依赖的内核函数在不同版本间可能变化,脚本要跟着调整。用 CO-RE 配合 BTF 能压住这类移植问题,编译时只记录字段访问意图,加载时用运行内核的 BTF 信息重定位偏移,同一份目标文件就能跨内核版本使用,也不再依赖内核头文件。容器里跑追踪需要相应权限,不要因此放宽整个节点的安全策略。Hubble 只能看到它所在数据面处理过的流量,绕过 Cilium 数据面的路径不在观测范围内。
常见问题
问,没装 Cilium 能不能排查。可以用 bpftrace 从进程侧入手,代价是没有策略判定这类集群语义。
问,追踪会影响业务性能吗。连接级探针触发少,开销一般可忽略。
问,输出的地址是集群内虚拟地址怎么办。按工作负载标签映射回具体工作负载,再回到进程侧确认发起方。