《Kubernetes网络权威指南》读书笔记 | 岂止iptables:Kubernetes Service官方实现细节探秘
Posted COCOgsta
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Kubernetes网络权威指南》读书笔记 | 岂止iptables:Kubernetes Service官方实现细节探秘相关的知识,希望对你有一定的参考价值。
书籍来源:《Kubernetes网络权威指南:基础、原理与实践》
一边学习一边整理读书笔记,并与大家分享,侵权即删,谢谢支持!
附上汇总贴:《Kubernetes网络权威指南》读书笔记 | 汇总_COCOgsta的博客-CSDN博客
运行在每个节点上的Kube-proxy会监控Service和Endpoints的更新,并调用其Load Balancer模块在主机上刷新路由转发规则。
Kube-proxy的Load Balancer模块实现有userspace、iptables和IPVS三种,当前主流的实现方式是iptables和IPVS。随着iptables在大规模环境下暴露出了扩展性和性能问题,越来越多的厂商开始使用IPVS模式。
4.1.1 userspace模式
Kube-proxy的userspace模式是通过Kube-proxy用户态程序实现Load Balancer的代理服务。userspace模式是Kube-proxy 1.0之前版本的默认模式。由于转发发生在用户态,效率自然不太高,而且容易丢包。
4.1.2 iptables模式
从Kubernetes 1.1版本开始,增加了iptables模式,在1.2版本中它正式替代userspace模式成为默认模式。Kube-proxy iptables模式的原理如图4-3所示。
图4-3 Kube-proxy iptables模式的原理
iptables模式与userspace模式最大的区别在于,Kube-proxy利用iptables的DNAT模块,实现了Service入口地址到Pod实际地址的转换,免去了一次内核态到用户态的切换。
iptables模式最主要的链是KUBE-SERVICES、KUBE-SVC-*和KUBE-SEP-*。
- KUBE-SERVICES链是访问集群内服务的数据包入口点,它会根据匹配到的目标IP:port将数据包分发到相应的KUBE-SVC-*链;
- KUBE-SVC-*链相当于一个负载均衡器,它会将数据包平均分发到KUBE-SEP-*链。每个KUBE-SVC-*链后面的KUBE-SEP-*链都和Service的后端Pod数量一样;
- KUBE-SEP-*链通过DNAT将连接的目的地址和端口从Service的IP:port替换为后端Pod的IP:port,从而将流量转发到相应的Pod。
图4-4演示了从客户端Pod到不同节点上的服务器Pod的流量路径。客户端通过172.16.12.100:80连接到服务。每个节点上的Kube-proxy进程会根据Service和对应的Endpoints创建一系列的iptables规则,以将流量重定向到相应Pod(例如10.255.255.202:8080)。
图4-4 Kube-proxy iptables模式的工作流
iptables模式与userspace模式相比虽然在稳定性和性能上均有不小的提升,但因为iptable使用NAT完成转发,也存在不可忽视的性能损耗。另外,当集群中存在上万服务时,Node上的iptables rules会非常庞大,对管理是个不小的负担,性能还会大打折扣。
iptables的SNAT
既然利用iptables做了一次DNAT,为了保证回程报文能够顺利返回,需要做一次SNAT。Kube-proxy创建的对应iptables规则形如:
在KUBE-POSTROUTING链中,对节点上匹配MARK标记(0x4000/0x4000)的数据包在离开节点时进行一次SNAT,即MASQUERADE(用节点IP替换包的源IP)。
4.1.3 IPVS模式
IPVS是LVS的负载均衡模块,亦基于netfilter,但比iptables性能更高,具备更好的可扩展性。Kube-proxy的IPVS模式在Kubernetes 1.11版本达到稳定。
既然Kube-proxy已经有了iptables模式,为什么Kubernetes还选择IPVS呢?iptables纯粹是为防火墙而设计的,并且底层路由表的实现是链表,对路由规则的增删改查操作都涉及遍历一次链表。
尽管Kubernetes在1.6版本中已经支持5000个节点,但使用iptables模式的Kube-proxy实际上是将集群扩展到5000个节点的最大瓶颈。
另外,使用IPVS做集群内服务的负载均衡可以解决iptables带来的性能问题。IPVS专门用于负载均衡,并使用更高效的数据结构(散列表)。
- IPVS的工作原理
IPVS是Linux内核实现的四层负载均衡,是LVS负载均衡模块的实现。
IPVS支持TCP、UDP、SCTP、IPv4、IPv6等协议,也支持多种负载均衡策略,例如rr、wrr、lc、wlc、sh、dh、lblc等。IPVS通过persistent connection调度算法原生支持会话保持功能。LVS的工作原理如图4-6所示。
图4-6 LVS的工作原理
由于IPVS的DNAT发生在netfilter的INPUT链,因此如何让网路报文经过INPUT链在IPVS中就变得非常重要了。一般有两种解决方法,一种方法是把服务的虚IP写到本机的本地内核路由表中;另一种方法是在本机创建一个dummy网卡,然后把服务的虚IP绑定到该网卡上。Kubernetes使用的是第二种方法,详见下文。
IPVS支持三种负载均衡模式:Direct Routing(简称DR)、Tunneling(也称ipip模式)和NAT(也称Masq模式)。
DR
IPVS的DR模式如图4-7所示。DR模式是应用最广泛的IPVS模式,它工作在L2,即通过MAC地址做LB,而非IP地址。在DR模式下,要求IPVS的Director和客户端在同一个局域网内。另外,DR不支持端口映射,无法支撑Kubernetes Service的所有场景。
图4-7 IPVS的DR模式
Tunneling
IPVS的Tunneling模式就是用IP包封装IP包,因此也称ipip模式,如图4-8所示。Tunneling模式下的报文不经过IPVS Director,而是直接回复给客户端。Tunneling模式同样不支持端口映射。
图4-8 IPVS的Tunneling模式
NAT
IPVS的NAT模式支持端口映射,回程报文需要经过IPVS Director,因此也称Masq(伪装)模式,如图4-9所示。Kubernetes在用IPVS实现Service时用的正是NAT模式。
图4-9 IPVS的NAT模式
- Kube-proxy IPVS模式参数
在运行基于IPVS的Kube-proxy时,需要注意以下参数:
-
--proxy-mode:除了现有的userspace和iptables模式,IPVS模式通过--proxy-mode=ipvs进行配置;
-
--ipvs-scheduler:用来指定IPVS负载均衡算法,如果不配置则默认使用roundrobin(rr)算法。
在运行IPVS模式的Kube-proxy前,请确保主机上已经加载了IPVS所需的所有内核模块,如下所示:
如果要在Kubernetes 1.11之前使用IPVS模式的Kube-proxy,需要打开Kubernetes的特性开关,形如--feature-gates=SupportIPVSProxyMode=true。
- IPVS模式实现原理
Kube-proxy IPVS模式的工作原理如图4-10所示。
图4-10 Kube-proxy IPVS模式的工作原理
一旦创建一个Service和Endpoints,IPVS模式的Kube-proxy会做以下三件事情。
(1)确保一块dummy网卡(kube-ipvs0)存在。为什么要创建dummy网卡?因为IPVS的netfilter钩子挂载INPUT链,我们需要把Service的访问IP绑定在dummy网卡上让内核“觉得”虚IP就是本机IP,进而进入INPUT链。
(2)把Service的访问IP绑定在dummy网卡上。
(3)通过socket调用,创建IPVS的virtual server和real server,分别对应Kubernetes的Service和Endpoints。
下面我们用一个例子来说明:
需要注意的是,Kubernetes服务和IPVS virtual server的映射关系是“1∶N”。例如,Load Balancer类型的Service有两个服务访问IP,分别是Cluster IP和Load Balancer IP,IPVS模式的Kube-proxy将创建两个IPVS virtual server,其中一个对应Cluster IP,另一个对应Load Balancer IP。Kubernetes的Endpoint(IP+端口)与IPVS real server之间的映射关系是“1∶1”。
删除Kubernetes的Service将触发删除相应的IPVS virtual server、IPVS real server和绑定在dummy网卡上的IP地址。
IPVS虽然有三种代理模式NAT、ipip和DR,但只有NAT模式支持端口映射。因此,Kube-proxy的IPVS使用了NAT模式,为的就是支持端口映射。一个IPVS服务端口3080到Pod端口8080的映射的样例如下:
- IPVS模式中的iptables和ipset
IPVS用于流量转发,它无法处理Kube-proxy中的其他问题,例如包过滤、SNAT等。具体来说,IPVS模式的Kube-proxy将在以下4种情况下依赖iptables:
- Kube-proxy配置启动参数masquerade-all=true,即集群中所有经过Kube-proxy的包都做一次SNAT;
- Kube-proxy启动参数指定集群IP地址范围;
- 支持Load Balancer类型的服务,用于配置白名单;
- 支持NodePort类型的服务,用于在包跨节点前配置MASQUERADE,类似于上文提到的iptables模式。
我们不想创建太多的iptables规则,因此使用ipset减少iptables规则,使得不管集群内有多少服务,IPVS模式下iptables规则的总数在5条以内。
4.1.4 iptables VS.IPVS
都说IPVS的性能优于iptables,表4-1为iptables和IPVS在刷新服务路由规则上的时延对比。
表4-1 iptables和IPVS在刷新服务路由规则上的时延对比
通过上表我们可以发现,IPVS刷新规则的时延明显要低iptables几个数量级。
从表4-2可以发现,相较于iptables,IPVS在端到端的吞吐率和平均时延方面均有不小的优化。值得一提的是,这是端到端的数据,包含了底层容器网络的RTT,还能有30%左右的性能提升。
表4-2 iptables和IPVS的吞吐率与平均时延对比
表4-3对比说明了Kube-proxy在IPVS和iptables模式下的资源消耗。
表4-3 Kube-proxy在IPVS和iptables模式下的资源消耗
不难看出,无论是资源消耗还是性能,IPVS模式均要优于iptables模式。
4.1.5 conntrack
在内核中,所有由netfilter框架实现的连接跟踪模块称作conntrack(connection tracking)。在DNAT的过程中,conntrack使用状态机启动并跟踪连接状态。为什么需要记录连接的状态呢?因为iptables/IPVS做了DNAT后需要记住数据包的目的地址被改成了什么,并且在返回数据包时将目的地址改回来。除此之外,iptables还可以依靠conntrack的状态(cstate)决定数据包的命运。其中最主要的4个conntrack状态如下:
(1)NEW:匹配连接的第一个包,这表示conntrack对该数据包的信息一无所知。通常发生在收到SYN数据包时。
(2)ESTABLISHED:匹配连接的响应包及后续的包,conntrack知道该数据包属于一个已建立的连接。通常发生在TCP握手完成之后。
(3)RELATED:RELATED状态有点复杂,当一个连接与另一个ESTABLISHED状态的连接有关时,这个连接就被认为是RELATED。这意味着,一个连接要想成为RELATED,必须先有一条已经是ESTABLISHED状态的连接存在。这个ESTABLISHED状态连接再产生一个主连接之外的新连接,这个新连接就是RELATED状态。
(4)INVALID:匹配那些无法识别或没有任何状态的数据包,conntrack不知道如何处理它。该状态在分析Kubernetes故障的过程中起着重要的作用。
在Pod和Service之间的TCP数据流路径如图4-11所示。
图4-11 Pod和Service之间的TCP数据流路径
TCP连接的生命周期分析如下:
- 左边的客户端发送数据包到Service:192.168.0.2:80;
- 数据包通过本地节点的iptables规则,目的地址被改为Pod的地址:10.0.1.2:80;
- 提供服务的Pod处理完数据包后返回响应包给客户端:10.0.0.2;
- 数据包到达客户端所在的节点后,被conntrack模块识别并将源地址改为:
192.169.0.2:80;
- 客户端接收到响应包。
4.1.6 小结
Kube-proxy实现的是分布式负载均衡,而非集中式负载均衡。何谓分布式负载均衡器呢?就是每个节点都充当一个负载均衡器,每个节点上都会被配置一模一样的转发规则。
上文提到,受制于iptables的实现,iptables模式的转发策略底层实现其实就是随机法,即将请求随机地分配到各个后端Pod(可能在不同节点上)。由概率统计理论得知,随着客户端调用服务端次数的增加,其实际效果越来越接近评价分配,也就是轮询(rr)的结果。缺点也比较明显,就是没有考虑机器的性能问题。根据木桶原理,Service的性能瓶颈会受性能最差的节点影响。那么,支持多种Load Balancer算法的IPVS模式呢?例如,lc(最小连接数)策略能否奏效?受制于Kube-proxy的分布式负载均衡架构,恐怕很难。同一个后端Pod可能有不同的Kube-proxy把请求转发给它,因此任何一个Kube-proxy都无法准确估计其后端Pod的连接数,故最小连接数这种转发策略无法派上用场。不过,可以尝试IPVS模式的sed(最短时延)转发策略。
以上是关于《Kubernetes网络权威指南》读书笔记 | 岂止iptables:Kubernetes Service官方实现细节探秘的主要内容,如果未能解决你的问题,请参考以下文章
《Kubernetes网络权威指南》读书笔记 | iptables
《Kubernetes网络权威指南》读书笔记 | 打通CNI与Kubernetes:Kubernetes网络驱动
《Kubernetes网络权威指南》读书笔记 | Kubernetes网络策略:为你的应用保驾护航
《Kubernetes网络权威指南》读书笔记 | 最常用的Docker网络技巧