基于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 +端口 loadBalancerSourceRanges | Drop packets for Load Balancer type Service with loadBalancerSourceRanges specified |
KUBE-LOAD-BALANCER-SOURCE-CIDR | 负载均衡器入口IP +端口+源CIDR | accept packets for Load Balancer type Service with loadBalancerSourceRanges specified |
KUBE-NODE-PORT-TCP | NodePort类型服务TCP端口 | 伪装到NodePort(TCP)的数据包 |
KUBE-NODE-PORT-LOCAL-TCP | NodePort类型服务TCP端口 externalTrafficPolicy=local | 通过以下方式接受到NodePort Service的数据包 externalTrafficPolicy=local |
KUBE-NODE-PORT-UDP | NodePort类型服务UDP端口 | 伪装到NodePort(UDP)的数据包 |
KUBE-NODE-PORT-LOCAL-UDP | NodePort类型服务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 故事