作者:马楠
笔者在学习kubernetes的kube-proxy的时候,kube-proxy具有三种proxy mode:
在Kubernetes v1.8.0-beta.0后引入的ipvs mode, 官方文档宣称其有更好的性能和更多的选项。但ipvs是什么呢,笔者作为网络方面的小白,这里并不打算恶补所有的网络知识,但ipvs不研究一下,后面也无法继续下去,所以本文是我学习ipvs的一个总结,可能类似的文章已经很多,能符合大家的期望最好,不到之处,也望各位看官一笑而过。
那什么是IPVS呢, IPVS(IP Virtual Server)是构建于Netfilter之上,作为Linux内核的一部分提供传输层负载均衡的模块。
提IPVS就不得不提LVS,IPVS模块是LVS集群的核心软件模块,它安装在LVS集群作为负载均衡的主节点上,虚拟出一个IP地址和端口对外提供服务, 把基于TCP或UDP的请求重定向到后面的真实的工作服务器。下文会对LVS, IPVS做比较详细的展开。
LVS的英文全称是Linux Virtual Server,即Linux虚拟服务器, 该项目致力于为Linux构建一个高性能、高可用的集群服务。现在主要被用做IPVS(advanced IP load balancing software)。它是我们国家的章文嵩博士的一个开源项目。在linux内存2.6中,它已经成为内核的一部分,在此之前的内核版本则需要重新编译内核。 LVS一般用于实现四层的负载均衡集群。
这里的“四层”指的是OSI七层模型中的第四层——传输层。 先看一下图吧:
如上图,一个数据从A节点传送到B节点,在A节点上的数据经过从第七层到第一层的层层封装,通过物理链路到达B节点后,再经过从第一层到第七层的层层解封后,最终为进程所用。
那么到底什么是四层负载均衡呢,上图只能解释OSI七层的工作模式,甚至连其中的网络层做什么都没有展现出来,再来看一下下图:
OSI模型是一个高阶模型,它指导着计算机节点间通讯所需遵循的基本原则,而在其具体实现——TCP/IP模型上,TCP/IP四层模型与之相对应,可以看到,工作在第四层的协议是TCP/UDP协议,也就是说四层负载均衡,是主要作用于TCP协议报文之上,基于IP+端口来判断需要重定向的报文,并修改报文中目标IP地址以进行重定向的负载均衡方式。
从第一张图可知,第四层的报文是看不到真正的数据内容的,所以此种负载不会考虑消息能容,例如无法根据不同的URL地址重定向到特定主机,相对的,其效率较高。
NAT(Network Address Translation)即网络地址转换,其作用是通过数据报头的修改,使得位于企业内部的私有IP地址可以访问外网,以及外部用用户可以访问位于公司内部的私有IP主机。 VS/NAT模式的工作原理是多目标DNAT,通过Director修改请求报文中的目标地址和端口为LVS挑选出来的某RS的RIP和PORT实现转发。
(a). 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP (b). PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链 (c). IPVS比对数据包请求的服务是否为集群服务,若是,修改数据包的目标IP地址为后端服务器IP,然后将数据包发至POSTROUTING链。 此时报文的源IP为CIP,目标IP为RIP (d). POSTROUTING链通过选路,将数据包发送给Real Server (e). Real Server比对发现目标为自己的IP,开始构建响应报文发回给Director Server。 此时报文的源IP为RIP,目标IP为CIP (f). Director Server在响应客户端前,此时会将源IP地址修改为自己的VIP地址,然后响应给客户端。 此时报文的源IP为VIP,目标IP为CIP
DR模式也叫直接路由模式,该模式中LVS依然仅承担数据的入站请求以及根据算法选出合理的真实服务器,最终由后端真实服务器负责将响应数据包发送返回给客户端。 此模式中Director为请求报文重新封装一个MAC首部进行转发,源MAC地址是DIP所在接口的MAC,目标MAC是挑选出来的的某RS的RIP接口所在的MAC,IP首部不会发生变化(CIP/VIP)
(a). 客户请求在前端路由器发送ARP广播来获取Director的VIP所在网卡的MAC地址,获知后,在请求报文上封装MAC首部(源MAC是路由器接口的MAC,目标MAC是Director上VIP接口的MAC),保证将报文发送至Director (b). 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP,PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链 (c). IPVS比对数据包请求的服务是否为集群服务,若是,将请求报文(源地址CIP/目标地址VIP)再次封装一个MAC首部(源MAC是DIP的MAC/目标MAC是RIP的MAC),然后将数据包发至POSTROUTING链。 此时的源IP和目的IP均未修改,仅修改了源MAC地址为DIP的MAC地址,目标MAC地址为RIP的MAC地址 (d). 由于DS和RS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MAC地址为RIP的MAC地址,那么此时数据包将会发至Real Server (e). RS发现请求报文的MAC地址是自己的MAC地址,就接收此报文,拆了MAC首部,发现目标地址是VIP,于是继续向lo:0转发,最终到达用户空间的进程给予响应,开始构建响应报文,处理完成之后,将响应报文通过lo:0接口传送给eth0网卡然后向外发出。 此时的源IP地址为VIP,目标IP为CIP。此时可能需要另外一个路由器,如图vs/dr.png所示,RIP的网关指向此路由,向外转发 (f). 响应报文最终送达至客户端
有关arpingore和arpannounce的具体介绍可以参见 《Linux内核参数之arpignore和arpannounce》
VS/TUN模式貌似并不是一个主要的负载均衡应用模式,笔者作为非网络专家,这里只罗列简单的调查内容,供用时参考。但是,前面两种模式VS/DR以及VS/NAT是应该掌握的基础知识。
不修改请求报文的IP首部(源地址是CIP,目标地址是VIP),而是在原IP首部之外再封装一个IP首部(原地址是DIP,目标地址是挑选出来的RS的RIP)进行转发。
(a). 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP 。 (b). PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链 (c). IPVS比对数据包请求的服务是否为集群服务,若是,在请求报文的首部再次封装一层IP报文,封装源IP为为DIP,目标IP为RIP。然后发至POSTROUTING链。 此时源IP为DIP,目标IP为RIP (d). POSTROUTING链根据最新封装的IP报文,将数据包发至RS(因为在外层封装多了一层IP首部,所以可以理解为此时通过隧道传输)。 此时源IP为DIP,目标IP为RIP (e). RS接收到报文后发现是自己的IP地址,就将报文接收下来,拆除掉最外层的IP后,会发现里面还有一层IP首部,而且目标是自己的lo接口VIP,那么此时RS开始处理此请求,处理完成之后,通过lo接口送给eth0网卡,然后向外传递。 此时的源IP地址为VIP,目标IP为CIP (f). 响应报文最终送达至客户端
仅依据算法本身进行轮询调度
根据算法及RS的当前负载状态进行调度
ipvsadm 用法同iptables
管理集群服务
ipvsadm -A|E -t|u|f service-address [-s scheduler] E 修改
ipvsadm -D -t|u|f service-address
service-address
tcp: -t ip:port
udp: -u ip:port
fwm: -f mark
-s scheduler
管理集群服务中的RS
ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight]
ipvsadm -d -t|u|f service-address -r server-address
server-address
ip:port
lvs-type 要注意使用 什么模型
-g gateway dr
-i ipip tun
-m masquerade,nat
清空和查看
ipvsadm -C
ipvsadm -L|l [options]
-n numberic 基于数字格式显示地址和端口
-c connetcion 显示ipvs连接
--rate 速率
--stats 统计数据
--exact 精确值
保存和重载
ipvsadm -R
ipvsadm -S [n]
置零计数器
ipvsadm -Z [-t|u|f service-address]
例:
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
UDP master.mike.com:domain rr
-> 10.244.0.6:domain Masq 1 0 0
-> 10.244.0.7:domain Masq 1 0 0
对于UDP协议,有一个集群服务master.mike.com:domain,它有两个RS,分别为10.244.0.6和10.244.0.7, LVS是以轮询的方式把请求分配给这两台RS, 两台RS的工作模式是Masq,即VS/NAT
随着Kubernetes使用率的增长,其资源的可扩展性变得越来越重要。特别是服务的可扩展性对于开发者和那些有高负载的公司对Kubernetes的接纳程度来说是非常重要的。
Kube-proxy作为服务路由(Service routing)的构建块一直依赖于久经沙场的iptables来实现对核心服务类型(ClusterIP和NodePort)的支持。但是,iptables在对10000以上的Service的扩展性支持上显得非常的挣扎,因为iptables本身是为防火墙而设计的,并基于内部的(in-kernel)规则列表。
在Kubernetes 1.6的时候, 它已经可以支持5000个节点,导致这个数量的实际瓶颈就是kube-proxy中的iptables。举例来说,在一个5000节点的集群中全部使用NodePort类型的的service,如果我们创建2000个services,每个service对应10个pods,这将使每个节点上生成至少20000条记录,从而导致内核相当繁忙。
相对来说,使用基于IPVS的集群服务负载均衡就对这种情景游刃有余的多了。IPVS是专门为负载均衡而设计的,并使用了更高效的数据结构(hash tables),从而在底层几乎具有无限的可扩展性。
当创建一个ClusterIP类型的Service时, IPVS proixer做了以下三件事:
[root@master ~]# ip addr
...
8: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether 4a:4e:8d:52:b0:3b brd ff:ff:ff:ff:ff:ff
...
[root@master ~]# kubectl describe svc kubernetes
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP: 10.96.0.1
Port: https 443/TCP
TargetPort: 6443/TCP
Endpoints: 192.168.56.101:6443
Session Affinity: None
Events: <none>
[root@master ~]# ip addr
...
8: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether 4a:4e:8d:52:b0:3b brd ff:ff:ff:ff:ff:ff
inet 10.96.0.1/32 brd 10.96.0.1 scope global kube-ipvs0
valid_lft forever preferred_lft forever
...
[root@master ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
...
TCP 10.96.0.1:443 rr
-> 192.168.56.101:6443 Masq 1 4 0
...
注意这里Kubernetes Service与IPVS virtual server的比例是1:N的关系。考虑一个kubernetes Service有多个IP的场景,比如,一个External IP类型的Service就含有两个IP —— Cluster IP 和 External IP,这时候IPVS proxier就会创建2个IPVS virtual servers——一个给Cluster IP,另一个给External IP。
本文大量图文摘自以下文章,另附加作者自我总结,特此声明
马楠,曾就职于日资公司NTT DATA Beijing, 国企中体彩科技发展有限公司,现Oracle系统架构和性能服务团队成员。职场中扮演过多种角色,不会运维的程序员不是好的架构师。