Merbridge CNI 模式的出现,旨在能够更好地适配服务网格的功能。之前没有 CNI 模式时,Merbridge 能够做得事情比较有限。其中最大的问题是不能适配注入 Istio 的 Sidecar Annotation ,这就导致 Merbridge 无法排除某些端口或 IP 段的流量等。同时,由于之前 Merbridge 只处理 Pod 内部的连接请求,这就导致,如果是外部发送到 Pod 的流量,Merbridge 将无法处理。
为此,我们精心设计了 Merbridge CNI ,旨在解决这些问题。
01
其一,之前的 Merbridge 只有一个很小的控制面,其监听 Pod 资源,将当前节点的 IP 信息写入 local_pod_ips 的 map ,以供 connect 使用。但是,connect 程序由于工作在主机内核层,其无法知道当前正在处理的是哪个 Pod 的流量,就没法处理如 excludeOutboundPorts 等配置。为了能够适配注入 excludeOutboundPorts 的 Sidecar Annotation ,我们需要让 eBPF 程序能够得知当前正在处理哪个 Pod 的请求。
为此,我们设计了一套方法,与 CNI 配合,能够获取当前 Pod 的 IP ,以适配针对 Pod 的特殊配置。
其二,在之前的 Merbridge 版本中,只有 connect 会处理主机发起的请求,这在同一台主机上的 Pod 互相通讯时,是没有问题的。但是在不同主机之间通讯时就会出现问题,因为按照之前的逻辑,在跨节点通讯时流量不会被修改,这会导致在接收端还是离不开 iptables 。
这次,我们依靠 XDP 程序,解决入口流量处理的问题。因为 XDP 程序需要挂载网卡,所以也需要借助 CNI 。
这里我们将探讨 CNI 的工作原理,以及如何使用 CNI 来解决问题。
我们通过 CNI ,在 Pod 创建的时候,将 Pod 的 IP 信息写入一个 Map (mark_pod_ips_map),其 Key 为一个随机的值,Value 为 Pod 的 IP 。然后,在当前 Pod 的 NetNS 里面监听一个特殊的端口 39807 ,将 Key 使用 setsockopt 写入这个端口 socket 的 mark 。
在 eBPF 中,我们通过 bpf_sk_lookup_tcp 取得端口 39807 的 Mark 信息,然后从 mark_pod_ips_map 中即可取得当前 NetNS (也是当期 Pod) 的 IP 。
有了当前 Pod IP 之后,我们可以根据这个 Pod 的配置,确认流量处理路径 (比如 excludeOutboundPorts)。
同时,我们还****使用 Pod 优化了之前解决四元组冲突的方案,改为使用 bpf_bind 绑定源 IP ,目的 IP 直接使用 127.0.0.1 ,为了后续支持 IPv6 做准备。
同时,考虑到可能存在主机直接访问 Pod 的情况,也为了减小影响范围,我们选择将 XDP 程序附加到 Pod 的网卡上。通过借助 CNI 的能力,在创建 Pod 时进行附加操作。
CNI 模式默认被关闭,需要手动开启。
可以使用以下命令一键开启:
curl -sSL https://raw.githubusercontent.com/merbridge/merbridge/main/deploy/all-in-one.yaml | sed 's/--cni-mode=false/--cni-mode=true/g' | kubectl apply -f -
测试方法:ethtool -k <网卡> | grep tx-checksum-ipv4 为 on 表示开启。
如果需要使用注入 Istio perf benchmark 等工具进行测试性能,请开启 CNI 模式,否则会导致性能测试结果不准确。
项目地址:
****https://github.com/merbridge/merbridge
社区交流:
****https://join.slack.com/t/merbridge/shared_invite/zt-11uc3z0w7-DMyv42eQ6s5YUxO5mZ5hwQ
微信社群:
扫码添加微信
备注 [ Merbridge ] ,加入讨论群
本文作者
刘齐均 (Kebe Liu)
「 DaoCloud 道客」服务网格技术专家,Istio 社区指导委员会成员,Istio 及 Kubernetes 代码贡献者,Merbridge 开源项目发起人