Kube-proxy 是 kubernetes 工作节点上的一个网络代理组件,运行在每个节点上。

Kubernetes 日志收集管理 kubeproxy日志_响应时间

Kube-proxy维护节点上的网络规则,实现了Kubernetes Service 概念的一部分 。它的作用是使发往 Service 的流量(通过ClusterIP和端口)负载均衡到正确的后端Pod。

工作原理

kube-proxy 监听 API server 中 资源对象的变化情况,包括以下三种:

  • service
  • endpoint/endpointslices
  • node

然后根据监听资源变化操作代理后端来为服务配置负载均衡。

Kubernetes 日志收集管理 kubeproxy日志_代理模式_02

如果你的 kubernetes 使用EndpointSlice,那么kube-proxy会监听EndpointSlice,否则会监听Endpoint。

如果你启用了服务拓扑,那么 kube-proxy 也会监听 node 信息 。服务拓扑(Service Topology)可以让一个服务基于集群的 Node 拓扑进行流量路由。 例如,一个服务可以指定流量是被优先路由到一个和客户端在同一个 Node 或者在同一可用区域的端点。

代理模式

目前 Kube-proxy 支持4中代理模式:

  • userspace
  • iptables
  • ipvs
  • kernelspace

其中 kernelspace 专用于windows,userspace 是早期版本的实现,本文我们不作过多阐述。

iptables(通过apiserver监听svc和endpoints/endpointslices资源生成iptables规则——nat表)

iptables是一种Linux内核功能,旨在成为一种高效的防火墙,具有足够的灵活性来处理各种常见的数据包操作和过滤需求。它允许将灵活的规则序列附加到内核的数据包处理管道中的各种钩子上。

在iptables模式下,kube-proxy将规则附加到“ NAT预路由”钩子上,以实现其NAT和负载均衡功能。这种方法很简单,使用成熟的内核功能,并且可以与通过iptables实现网络策略的组件“完美配合”。

Kubernetes 日志收集管理 kubeproxy日志_Pod_03

默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。

如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。

但是,kube-proxy对iptables规则进行编程的方式是一种O(n)复杂度的算法,其中n与集群大小(或更确切地说,服务的数量和每个服务背后的后端Pod的数量)成比例地增长)。

ipvs(通过apiserver监听svc和endpoints/endpointslices资源生成ipvs和iptables规则)

IPVS是专门用于负载均衡的Linux内核功能。在IPVS模式下,kube-proxy可以对IPVS负载均衡器进行编程,而不是使用iptables。这非常有效,它还使用了成熟的内核功能,并且IPVS旨在均衡许多服务的负载。它具有优化的API和优化的查找例程,而不是一系列顺序规则。 结果是IPVS模式下kube-proxy的连接处理的计算复杂度为O(1)。换句话说,在大多数情况下,其连接处理性能将保持恒定,而与集群大小无关。

与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

Kubernetes 日志收集管理 kubeproxy日志_响应时间_04

IPVS提供了更多选项来平衡后端Pod的流量。 这些是:

  • rr: round-robin
  • lc: least connection (smallest number of open connections)
  • dh: destination hashing
  • sh: source hashing
  • sed: shortest expected delay
  • nq: never queue

IPVS的一个潜在缺点是,与正常情况下的数据包相比,由IPVS处理的数据包通过iptables筛选器钩子的路径不同。如果打算将IPVS与其他使用iptables的程序一起使用,则需要研究它们是否可以一起正常工作。 不过Ipvs代理模式已经推出很久了,很多组件已经适配的很好了,比如Calico。

性能对比

TIGERA 公司 从响应时间CPU使用率两个角度对两种代理模式进行了对比。在专用节点上运行了一个“客户端”微服务Pod,它每秒向Kubernetes服务生成1000个请求,该请求由集群中其他节点上运行的10个“服务器”微服务Pod承载。然后,在iptables和IPVS模式下,使用各种数量的Kubernetes服务(每个服务有10个Pod支持),最多10,000个服务(带有100,000个服务后端)来测量客户端节点上的性能。

Round-Trip 响应时间

Kubernetes 日志收集管理 kubeproxy日志_Pod_05

  • 在超过1,000个服务(10,000个后端Pod)之前,iptables和IPVS之间的平均往返响应时间之间的差异微不足道。
  • 仅当不使用keepalive连接时,平均往返响应时间才有差异。

CPU消耗

Kubernetes 日志收集管理 kubeproxy日志_响应时间_06

  • iptables和IPVS之间的CPU使用率差异不明显,直到超过1,000个服务(带有10,000个后端Pod)为止。
  • 在10,000个服务(具有100,000个后端pod)的情况下,使用iptables的CPU的增加量约为内核的35%,而使用IPVS的CPU的增加量约为内核的8%。

总结

对于iptables和IPVS模式,kube-proxy的响应时间开销与建立连接相关,而不是与在这些连接上发送的数据包或请求的数量有关。这是因为Linux使用的连接跟踪(conntrack)能够非常有效地将数据包与现有连接进行匹配。如果数据包在conntrack中匹配,则无需检查kube-proxy的iptables或IPVS规则即可确定该如何处理。

在集群中不超过1000个服务的时候,iptables 和 ipvs 并无太大的差异。而且由于iptables 与网络策略实现的良好兼容性,iptables 是个非常好的选择。(通过与其他公司k8s运维人员交流,大部分都会选择使用ipvs模式)

当你的集群服务超过1000个时,而且服务之间链接大多没有开启keepalive,IPVS模式可能是一个不错的选择。

发展趋势

个人总结 kube-proxy 未来发展可能会朝着以下两个方向:

  • 接口化,类似于cni。kube-proxy 只实现主体框架和接口规范,社区可以有iptables,ipvs,ebpf,nftables等具体实现。

Kubernetes以具备可扩展性而著名。截止到目前,Kube-proxy 几乎是所有k8s组件里边最没有接口化的一个组件。如果想给 kube-proxy 增加一种代理模式,必须代码侵入。所以社区有人想将 nftables 做为 kube-proxy 的一种后端,该 pr 至今没有被merge。

nftables是一个新式的数据包过滤框架,旨在替代现用的iptables、ip6tables、arptables和ebtables的新的包过滤框架。nftables旨在解决现有{ip/ip6}tables工具存在的诸多限制。相对于旧的iptables,nftables最引人注目的功能包括:改进性能、支持查询表、事务型规则更新、所有规则自动应用等等。

  • 无 kube-proxy。交给容器网络框架实现。

践行该观点的容器网络框架非cilium莫属。

Cilium 正在通过 ebpf 实现 kube-proxy 提供的功能。不过由于 ebpf 对 os 内核版本要求比较高,所以一些低版本内核是无法支持的。

CNI chaining 允许cilium 和其他cni容器网络组建结合使用。通过Cilium CNI chaining ,基本网络连接和IP地址管理由非Cilium CNI插件管理,但是Cilium将eBPF程序附加到由非Cilium插件创建的网络设备上,以提供L3 / L4 / L7网络可见性和策略强制执行和其他高级功能,例如透明加密。

Kubernetes 日志收集管理 kubeproxy日志_代理模式_07

而且该趋势已经被多家公有云厂商认可和支持。比如阿里云结合 terway CNI 和 Cilium,使用cilium提供Kubernetes的Service和NetworkPolicy实现。

Kubernetes 日志收集管理 kubeproxy日志_Kubernetes 日志收集管理_08