基于IPVS的集群内负载均衡深潜

作者:杜军(华为),谢海滨(华为),魏亮(华为)

编者注:这篇文章是 系列深入文章 Kubernetes 1.11的新功能

介绍

Kubernetes 1.11发布博客文章 ,我们宣布基于IPVS的群集内服务负载平衡将逐步升级为通用。在此博客中,我们将带您深入了解该功能。

什么是IPVS?

IPVS (IP虚拟服务器)构建在Netfilter之上,并作为Linux内核的一部分实现传输层负载平衡。

IPVS已集成到LVS(Linux虚拟服务器)中,在此服务器上运行,并充当真实服务器群集前面的负载平衡器。 IPVS可以将对基于TCP和UDP的服务的请求定向到真实服务器,并使真实服务器的服务在单个IP地址上显示为虚拟服务。因此,IPVS自然支持Kubernetes服务。

为什么为Kubernetes使用IPVS?

随着Kubernetes的使用不断增长,其资源的可伸缩性变得越来越重要。特别是,服务的可伸缩性对于运行大量工作负载的开发人员/公司采用Kubernetes至关重要。

服务路由的构建模块Kube-proxy依靠经过艰苦努力的iptables来实现核心支持的服务类型,例如ClusterIP和NodePort。但是,iptables很难扩展到成千上万的服务,因为它纯粹是为防火墙目的而设计的,并且基于内核规则列表。

尽管Kubernetes在v1.6版本中已经支持5000个节点,但是带有iptables的kube-proxy实际上是将集群扩展到5000个节点的瓶颈。一个示例是,在5000个节点的群集中使用NodePort Service,如果我们有2000个服务,而每个服务有10个Pod,则这将在每个工作节点上至少产生20000个iptable记录,这会使内核变得非常繁忙。

另一方面,使用基于IPVS的群集内服务负载平衡在这种情况下会很有帮助。 IPVS是专门为负载平衡而设计的,并使用更有效的数据结构(哈希表),允许在后台进行几乎无限的扩展。

基于IPVS的Kube代理

参数变更

参数:--proxy-mode In addition to existing userspace and iptables modes, IPVS mode is configured via --proxy-mode=ipvs. It implicitly uses IPVS NAT mode for service port mapping.

参数:--ipvs-scheduler

A new kube-proxy parameter has been added to specify the IPVS load balancing algorithm, with the parameter being --ipvs-scheduler. If it’s not configured, then round-robin (rr) is the default value.

  • rr:循环
  • lc:最少连接
  • dh:目标哈希
  • sh:源哈希
  • sed:最短的预期延迟
  • nq:永不排队

将来,我们可以实现特定于服务的调度程序(可能通过注释),该调度程序具有更高的优先级并覆盖该值。

参数: --cleanup-ipvs Similar to the --cleanup-iptables parameter, if true, cleanup IPVS configuration and IPTables rules that are created in IPVS mode.

参数: --ipvs-sync-period IPVS规则刷新的最大间隔(例如“ 5s”,“ 1m”)。必须大于0。

参数: --ipvs-min-sync-period IPVS规则刷新的最小间隔(例如“ 5s”,“ 1m”)。必须大于0。

参数: --ipvs-exclude-cidrs 逗号分隔的CIDR列表,在清理IPVS规则时IPVS代理不应触摸此CIDR,因为IPVS代理无法将kube-proxy创建的IPVS规则与用户原始IPVS规则区分开。如果您在环境中使用具有自己的IPVS规则的IPVS代理,则应指定此参数,否则将清除原始规则。

设计注意事项

IPVS服务网络拓扑

创建ClusterIP类型服务时,IPVS代理将执行以下三件事:

  • 确保节点中存在一个虚拟接口,默认为kube-ipvs0
  • 将服务IP地址绑定到虚拟接口
  • 分别为每个服务IP地址创建IPVS虚拟服务器

这里有一个例子:

# kubectl describe svc nginx-service
Name:			nginx-service
...
Type:			ClusterIP
IP:			    10.102.128.4
Port:			http	3080/TCP
Endpoints:		10.244.0.235:8080,10.244.1.237:8080
Session Affinity:	None

# ip addr
...
73: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff
    inet 10.102.128.4/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever

# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn     
TCP  10.102.128.4:3080 rr
  -> 10.244.0.235:8080            Masq    1      0          0         
  -> 10.244.1.237:8080            Masq    1      0          0   

Please note that the relationship between a Kubernetes Service and IPVS virtual servers is 1:N. For example, consider a Kubernetes Service that has more than one IP address. An External IP type Service has two IP addresses - ClusterIP and External IP. Then the IPVS proxier will create 2 IPVS virtual servers - one for Cluster IP and another one for External IP. The relationship between a Kubernetes Endpoint (each IP+Port pair) and an IPVS virtual server is 1:1.

删除Kubernetes服务将触发相应IPVS虚拟服务器,IPVS真实服务器及其绑定到虚拟接口的IP地址的删除。

端口映射

IPVS中有三种代理模式:NAT(masq),IPIP和DR。仅NAT模式支持端口映射。 Kube-proxy利用NAT模式进行端口映射。以下示例显示IPVS将服务端口3080映射到Pod端口8080。

TCP  10.102.128.4:3080 rr
  -> 10.244.0.235:8080            Masq    1      0          0         
  -> 10.244.1.237:8080            Masq    1      0       

会话亲和力

IPVS支持客户端IP会话亲缘关系(持久连接)。当服务指定会话亲缘关系时,IPVS代理将在IPVS虚拟服务器中设置超时值(默认为180min = 10800s)。例如:

# kubectl describe svc nginx-service
Name:			nginx-service
...
IP:			    10.102.128.4
Port:			http	3080/TCP
Session Affinity:	ClientIP

# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.102.128.4:3080 rr persistent 10800

IPVS Proxier中的iptables和ipset

IPVS用于负载平衡,并且不能处理kube-proxy中的其他解决方法,例如数据包过滤,发夹式假扮技巧,SNAT等

IPVS代理在上述情况下利用iptables。具体来说,在以下4种情况下,ipvs proxier将依赖iptables:

  • kube-proxy以--masquerade-all = true开头
  • 在kube-proxy启动中指定集群CIDR
  • 支持负载均衡器类型服务
  • 支持NodePort类型服务

但是,我们不想创建太多iptables规则。因此,为了减少iptables规则,我们采用ipset。下表是IPVS代理维护的ipset列表:

设定名称成员用法
KUBE-CLUSTER-IP所有服务IP +端口masquerade for cases that masquerade-all=true or clusterCIDR specified
KUBE-LOOP-BACK所有服务IP +端口+ IP化装发夹问题的化装舞会
KUBE-EXTERNAL-IP服务外部IP +端口伪装到外部IP的数据包
KUBE-LOAD-BALANCER负载均衡器入口IP +端口将数据包伪装成负载均衡器类型的服务
KUBE-LOAD-BALANCER-LOCAL负载均衡器入口IP +端口 externalTrafficPolicy=local接受数据包到负载均衡器 externalTrafficPolicy=local
KUBE-LOAD-BALANCER-FW负载均衡器入口IP +端口 loadBalancerSourceRangesDrop packets for Load Balancer type Service with loadBalancerSourceRanges specified
KUBE-LOAD-BALANCER-SOURCE-CIDR负载均衡器入口IP +端口+源CIDRaccept packets for Load Balancer type Service with loadBalancerSourceRanges specified
KUBE-NODE-PORT-TCPNodePort类型服务TCP端口伪装到NodePort(TCP)的数据包
KUBE-NODE-PORT-LOCAL-TCPNodePort类型服务TCP端口 externalTrafficPolicy=local通过以下方式接受到NodePort Service的数据包 externalTrafficPolicy=local
KUBE-NODE-PORT-UDPNodePort类型服务UDP端口伪装到NodePort(UDP)的数据包
KUBE-NODE-PORT-LOCAL-UDPNodePort类型服务UDP端口 externalTrafficPolicy=local通过以下方式接受到NodePort Service的数据包 externalTrafficPolicy=local

通常,对于IPVS代理,无论我们有多少服务/窗格,iptables规则的数量都是静态的。

在IPVS模式下运行kube-proxy

Currently, local-up scripts, GCE scripts, and kubeadm support switching IPVS proxy mode via exporting environment variables (KUBE_PROXY_MODE=ipvs) or specifying flag (--proxy-mode=ipvs). Before running IPVS proxier, please ensure IPVS required kernel modules are already installed.

ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack_ipv4

Finally, for Kubernetes v1.10, feature gate SupportIPVSProxyMode is set to true by default. For Kubernetes v1.11, the feature gate is entirely removed. However, you need to enable --feature-gates=SupportIPVSProxyMode=true explicitly for Kubernetes before v1.10.

参与其中

参与Kubernetes的最简单方法是加入众多方法之一 特别兴趣小组 (SIG)符合您的兴趣。您有什么想向Kubernetes社区广播的内容吗?在我们的每周分享您的声音 社区会议,并通过下面的渠道。

感谢您一直以来的反馈和支持。 发表问题(或回答问题) 堆栈溢出 加入社区门户以倡导 K8端口在推特上关注我们 @Kubernetesio 有关最新更新 与社区聊天 松弛 分享您的Kubernetes 故事