Kubernetes Kube-proxy解析

在Kubernetes集群的每个Node上都会运行一个kube-proxy服务进程,我们可以把这个进程看作Service的透明代理兼负载均衡器,其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。此外,Service的Cluster IP与NodePort等概念是kube-proxy服务通过iptables的NAT转换实现的,kube-proxy在运行过程中动态创建与Service相关的iptables规则,这些规则实现了将访问服务(Cluster IP或NodePort)的请求负载分发到后端Pod的功能。

kube-proxy的发展

kube-proxy第一版

起初,kube-proxy进程是一个真实的TCP/UDP代理,类似HA Proxy,负责从Service到Pod的访问流量的转发,这种模式被称为userspace(用户空间代理)模式。

当某个Pod以Cluster IP方式访问某个Service的时候, 这个流量会被Pod所在本机的iptables转发到本机的kube-proxy进程, 然后由kube-proxy建立起到后端Pod的TCP/UDP连接, 随后将请求转发到某个后端Pod上, 并在这个过程中实现负载均衡功能。

imgimg

kube-proxy 第二版

img

Kubernetes从1.2版本开始, 将iptables作为kubeproxy的默认模式。 iptables模式下的kube-proxy不再起到Proxy的作用,其核心功能: 通过API Server的Watch接口实时跟踪Service与Endpoint的变更信息, 并更新对应的iptables规则, Client的请求流量则通过iptables的NAT机制“直接路由”到目标Pod。

直接修改iptables规则, 则也可以实现kube-proxy的功能, 并且是全自动模式的。 与第1代的userspace模式相比, iptables模式完全工作在内核态, 不用再经过用户态的kube-proxy中转, 因而性能更强。

iptables模式虽然实现起来简单, 但存在无法避免的缺陷: 在集群中的Service和Pod大量增加以后, iptables中的规则会急速膨胀, 导致性能显著下降, 在某些极端情况下甚至会出现规则丢失的情况, 并且这种故障难以重现与排查, 于是Kubernetes从1.8版本开始引入第3代的IPVS(IP Virtual Server) 模式 。

kube-proxy 第三版

iptables与IPVS虽然都是基于Netfilter实现的, 但因为定位不同, 二者有着本质的差别: iptables是为防火墙而设计的; IPVS则专门用于高性能负载均衡, 并使用更高效的数据结构(Hash表) , 允许几乎无限的规模扩张, 因此被kube-proxy采纳为第三代模式 。

img

与iptables相比, IPVS拥有以下明显优势:

  • 为大型集群提供了更好的可扩展性和性能
  • 支持比iptables更复杂的复制均衡算法( 最小负载、 最少连接、加权等)
  • 支持服务器健康检查和连接重试等功能
  • 可以动态修改ipset的集合, 即使iptables的规则正在使用这个集合

由于IPVS无法提供包过滤、 airpin-masquerade tricks(地址伪装) 、SNAT等功能, 因此在某些场景(如NodePort的实现) 下还要与iptables搭配使用。 在IPVS模式下, kube-proxy又做了重要的升级, 即使用
iptables的扩展ipset, 而不是直接调用iptables来生成规则链。iptables规则链是一个线性的数据结构, ipset则引入了带索引的数据结构, 因此当规则很多时, 也可以很高效地查找和匹配。

主要的iptables规则

  • KUBE-CLUSTER-IP: 在masquerade-all=true或clusterCIDR指定的情况下对Service Cluster IP地址进行伪装, 以解决数据包欺骗问题 。
  • KUBE-EXTERNAL-IP: 将数据包伪装成Service的外部IP地址。
  • KUBE-LOAD-BALANCER、 KUBE-LOAD-BALANCERLOCAL: 伪装Load Balancer 类型的Service流量。
  • KUBE-NODE-PORT-TCP、 KUBE-NODE-PORT-LOCALTCP、 KUBE-NODE-PORTUDP、 KUBE-NODE-PORT-LOCAL-UDP:伪装NodePort类型的Service流量。