Kube-proxy 组件运行机制解析

2020-08-15 0 By admin

一、引子:Service对象和Kube-proxy进程

1.1、Service 资源对象

我们在前面已经了解到,为了支持集群的水平扩展、高可用性,Kubernetes 抽象出了Service的概念。Service是对一组 Pod 的抽象,它会根据访问策略(如负载均衡策略)来访问这组 Pod。
Kubernetes 在创建服务Service 时会为服务分配一个虚拟的IP地址,客户端通过访问这个虚拟的IP地址来访问服务,服务则负责将请求转发到后端的Pod上。

这不就是一个反向代理吗?没错,这就是一个反向代理。但是,它和普通的反向代理有一些不同:首先,它的IP地址是虚拟的,想从外面访问还需要一些技巧;其次,它的部署和启停是由Kubernetes统一自动管理的。

1.2、kube-proxy 对 Server对象的实现

在很多情况下,Service 只是一个概念,而真正将 Service 的作用落实的是它背后的 kube-proxy 服务进程。只有理解了 kube-proxy 的原理和机制,我们才能真正理解 Service 背后的实现逻辑。
在 Kubernetes 集群的每个 Node 上都会运行一个 kube-proxy 服务进程,我们可以把这个进程看作 Service 的透明代理兼负载均衡器,其核心功能是将到某个 Service 的访问请求转发到后端的多个 Pod 实例上。

此外,Service的 Cluster IP 与 NodePort 等概念是kube-proxy服务通过 iptables 的 NAT 转换实现的,kube-proxy在运行过程中动态创建与 Service 相关的 iptables 规则,这些规则实现了将访问服务(Cluster IP或NodePort)的请求负载分发到后端Pod的功能。

由于iptables机制针对的是本地的kube-proxy端口,所以在每个Node上都要运行kube-proxy组件,这样一来,在Kubernetes集群内部,我们可以在任意Node上发起对Service的访问请求。

综上所述,由于kube-proxy的作用,在Service的调用过程中客户端无须关心后端有几个Pod,中间过程的通信、负载均衡及故障恢复都是透明的。

二、Kube-proxy 进程发展的三个阶段

2.1、用户空间代理模式:类似HA Proxy

起初,kube-proxy进程是一个真实的 TCP/UDP 代理,类似 HA Proxy,负责从Service到Pod的访问流量的转发,这种模式被称为userspace(用户空间代理)模式。
当某个 Pod 以 Cluster IP 方式访问某个 Service 的时候,这个流量会被Pod所在本机的iptables转发到本机的kube-proxy进程,然后由kube-proxy建立起到后端 Pod 的TCP/UDP连接,随后将请求转发到某个后端Pod上,并在这个过程中实现负载均衡功能。
关于Cluster IP与Node Port的实现原理,以及kube-proxy与API Server的交互过程,由于这是最古老的kube-proxy的实现方式,所以不再赘述。

2.2、iptables 模式(内核空间模式)

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

根据Kubernetes的网络模型,一个Node上的Pod与其他Node上的Pod应该能够直接建立双向的TCP/IP通信通道,所以如果直接修改iptables规则,则也可以实现 kube-proxy 的功能,只不过后者更加高端,因为是全自动模式的。
与第1代的userspace模式相比,iptables模式完全工作在内核态,不用再经过用户态的kube-proxy中转,因而性能更强。

iptables模式虽然实现起来简单,但存在无法避免的缺陷:
在集群中的 Service 和 Pod 大量增加以后,iptables中的规则会急速膨胀,导致性能显著下降,在某些极端情况下甚至会出现规则丢失的情况,并且这种故障难以重现与排查,

2.3、扩展IPVS模式

由于Iptables 的缺陷,Kubernetes 从1.8版本开始引入第3代的IPVS(IP Virtual Server)模式。IPVS在Kubernetes 1.11中升级为GA稳定版。

iptables与 IPVS 虽然都是基于Netfilter实现的,但因为定位不同,二者有着本质的差别:

  • iptables是为防火墙而设计的。
  • IPVS则专门用于高性能负载均衡,并使用更高效的数据结构(Hash表),允许几乎无限的规模扩张,因此被kube-proxy采纳为第三代模式。

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

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

由于IPVS无法提供包过滤、airpin-masquerade tricks(地址伪装)、SNAT等功能,因此在某些场景(如NodePort的实现)下还要与iptables搭配使用。
在IPVS模式下,kube-proxy又做了重要的升级,即使用iptables的扩展ipset,而不是直接调用iptables来生成规则链。

三、IPVS模式结合Iptables使用说明

3.1、iptables 和 ipvs结合使用

iptables规则链是一个线性的数据结构,ipset则引入了带索引的数据结构,因此当规则很多时,也可以很高效地查找和匹配。
我们可以将ipset简单理解为一个IP(段)的集合,这个集合的内容可以是IP地址、IP网段、端口等,iptables可以直接添加规则对这个“可变的集合”进行操作,这样做的好处在于可以大大减少iptables规则的数量,从而减少性能损耗。
假设要禁止上万个IP访问我们的服务器,则用iptables的话,就需要一条一条地添加规则,会在iptables中生成大量的规则;但是用ipset的话,只需将相关的IP地址(网段)加入ipset集合中即可,这样只需设置少量的iptables规则即可实现目标。

3.2、默认Iptables 规则介绍

kube-proxy针对Service和Pod创建的一些主要的iptables规则如下:

  1. kube-cluster-ip:在masquerade-all=true或clustercidr指定的情况下对service cluster ip地址进行伪装,以解决数据包欺骗问题。
  2. kube-external-ip:将数据包伪装成service的外部ip地址。
  3. kube-load-balancer、kube-load-balancer-local:伪装load balancer 类型的service流量。
  4. kube-node-port-tcp、kube-node-port-local-tcp、kube-node-portudp、kube-node-port-local-udp:伪装nodeport类型的service流量。