使用IPVS实现Kubernetes入口流量负载均衡

    xiaoxiao2024-05-19  102

    新搭建的Kubernetes集群如何承接外部访问的流量,是刚上手Kubernetes时常常会遇到的问题。在公有云上,官方给出了比较直接的答案,使用LoadBalancer类型的Service,利用公有云提供的负载均衡服务来承接流量,同时在多台服务器之间进行负载均衡。而在私有环境中,如何正确的将外部流量引入到集群内部,却暂时没有标准的做法。本文将介绍一种基于IPVS来承接流量并实现负载均衡的方法,供大家参考。

    IPVS

    [IPVS]是[LVS]项目的一部分,是一款运行在Linux kernel当中的4层负载均衡器,性能异常优秀。根据这篇文章的介绍,使用调优后的内核,可以轻松处理每秒10万次以上的转发请求。目前在中大型互联网项目中,IPVS被广泛的使用,用于承接网站入口处的流量。

    Kubernetes Service

    Service是Kubernetes的基础概念之一,它将一组Pod抽象成为一项服务,统一的对外提供服务,在各个Pod之间实现负载均衡。Service有多种类型,最基本的ClusterIP类型解决了集群内部访问服务的需求,NodePort类型通过Node节点的端口暴露服务,再配合上LoadBalancer类型所定义的负载均衡器,实现了流量经过前端负载均衡器分发到各个Node节点暴露出的端口,再通过iptables进行一次负载均衡,最终分发到实际的Pod上这个过程。

    在Service的Spec中,externalIPs字段平常鲜有人提到,当把IP地址填入这个字段后,kube-proxy会增加对应的iptables规则,当有以对应IP为目标的流量发送到Node节点时,iptables将进行NAT,将流量转发到对应的服务上。一般情况下,很少会遇到服务器接受非自身绑定IP流量的情况,所以externalIPs不常被使用,但配合网络层的其他工具,它可以实现给Service绑定外部IP的效果。

    今天我们将使用externalIPs配合IPVS的DR(Direct Routing)模式实现将外部流量引入到集群内部,同时实现负载均衡。

    环境搭建

    为了演示,我们搭建了4台服务器组成的集群。一台服务器运行IPVS,扮演负载均衡器的作用,一台服务器运行Kubernetes Master组件,其他两台服务器作为Node加入到Kubernetes集群当中。搭建过程这里不详细介绍,大家可以参考相关的文档。

    所有服务器在172.17.8.0/24这个网段中。服务的VIP我们设定为172.17.8.201。整体架构如下图所示:

    接下来让我们来配置IPVS和Kubernetes。

    使用externalIPs暴露Kubernetes Service

    首先在集群内部运行2个nginx Pod用作演示。

    $ kubectl run nginx --image=nginx --replicas=2

    再将它暴露为Service,同时设定externalIPs字段

    $ kubectl expose deployment nginx --port 80 --external-ip 172.17.8.201

    查看iptables配置,确认对应的iptables规则已经被加入。

    $ sudo iptables -t nat -L KUBE-SERVICES -n Chain KUBE-SERVICES (2 references) target prot opt source destination KUBE-SVC-4N57TFCL4MD7ZTDA tcp -- 0.0.0.0/0 10.3.0.156 /* default/nginx: cluster IP */ tcp dpt:80 KUBE-MARK-MASQ tcp -- 0.0.0.0/0 172.17.8.201 /* default/nginx: external IP */ tcp dpt:80 KUBE-SVC-4N57TFCL4MD7ZTDA tcp -- 0.0.0.0/0 172.17.8.201 /* default/nginx: external IP */ tcp dpt:80 PHYSDEV match ! --physdev-is-in ADDRTYPE match src-type !LOCAL KUBE-SVC-4N57TFCL4MD7ZTDA tcp -- 0.0.0.0/0 172.17.8.201 /* default/nginx: external IP */ tcp dpt:80 ADDRTYPE match dst-type LOCAL KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- 0.0.0.0/0 10.3.0.1 /* default/kubernetes:https cluster IP */ tcp dpt:443 KUBE-NODEPORTS all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

    配置IPVS实现流量转发

    首先在IPVS服务器上,打开ipv4_forward。

    $ sudo sysctl -w net.ipv4.ip_forward=1

    接下来加载IPVS内核模块。

    $ sudo modprobe ip_vs

    将VIP绑定在网卡上。

    $ sudo ifconfig eth0:0 172.17.8.201 netmask 255.255.255.0 broadcast 172.17.8.255

    再使用ipvsadm来配置IPVS,这里我们直接使用Docker镜像,避免和特定发行版绑定。

    $ docker run --privileged -it --rm --net host luizbafilho/ipvsadm / # ipvsadm IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn / # ipvsadm -A -t 172.17.8.201:80 / # ipvsadm -a -t 172.17.8.201:80 -r 172.17.8.11:80 -g / # ipvsadm -a -t 172.17.8.201:80 -r 172.17.8.12:80 -g / # ipvsadm IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.17.8.201:http wlc -> 172.17.8.11:http Route 1 0 0 -> 172.17.8.12:http Route 1 0 0

    可以看到,我们成功建立了从VIP到后端服务器的转发。

    验证转发效果

    首先使用curl来测试是否能够正常访问nginx服务。

    $ curl http://172.17.8.201 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>

    接下来在172.17.8.11上抓包来确认IPVS的工作情况。

    $ sudo tcpdump -i any port 80 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes 04:09:07.503858 IP 172.17.8.1.51921 > 172.17.8.201.http: Flags [S], seq 2747628840, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1332071005 ecr 0,sackOK,eol], length 0 04:09:07.504241 IP 10.2.0.1.51921 > 10.2.0.3.http: Flags [S], seq 2747628840, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1332071005 ecr 0,sackOK,eol], length 0 04:09:07.504498 IP 10.2.0.1.51921 > 10.2.0.3.http: Flags [S], seq 2747628840, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1332071005 ecr 0,sackOK,eol], length 0 04:09:07.504827 IP 10.2.0.3.http > 10.2.0.1.51921: Flags [S.], seq 3762638044, ack 2747628841, win 28960, options [mss 1460,sackOK,TS val 153786592 ecr 1332071005,nop,wscale 7], length 0 04:09:07.504827 IP 10.2.0.3.http > 172.17.8.1.51921: Flags [S.], seq 3762638044, ack 2747628841, win 28960, options [mss 1460,sackOK,TS val 153786592 ecr 1332071005,nop,wscale 7], length 0 04:09:07.504888 IP 172.17.8.201.http > 172.17.8.1.51921: Flags [S.], seq 3762638044, ack 2747628841, win 28960, options [mss 1460,sackOK,TS val 153786592 ecr 1332071005,nop,wscale 7], length 0 04:09:07.505599 IP 172.17.8.1.51921 > 172.17.8.201.http: Flags [.], ack 1, win 4117, options [nop,nop,TS val 1332071007 ecr 153786592], length 0

    可以看到,由客户端172.17.8.1发送给172.17.8.201的封包,经过IPVS的中转发送给了172.17.8.11这台服务器,并经过NAT后发送给了10.2.0.3这个Pod。返回的封包不经过IPVS服务器直接从172.17.8.11发送给了172.17.8.1。说明IPVS的DR模式工作正常。重复多次测试可以看到流量分别从172.17.8.11和172.17.8.12进入,再分发给不同的Pod,说明负载均衡工作正常。

    与传统的IPVS DR模式配置不同的是,我们并未在承接流量的服务器上执行绑定VIP,再关闭ARP的操作。那是因为对VIP的处理直接发生在iptables上,我们无需在服务器上运行程序来承接流量,iptables会将流量转发到对应的Pod上。

    使用这种方法来承接流量,仅需要配置externalIPs为VIP即可,无需对服务器做任何特殊的设置,使用起来相当方便。

    总结

    在本文中演示了使用IPVS配合externalIPs实现将外部流量导入到Kubernetes集群中,并实现负载均衡的方法。希望可以帮助大家理解IPVS和externalIPs的工作原理,以便在恰当的场景下合理使用这两项技术解决问题。实际部署时,还需要考虑后台服务器可用性检查,IPVS节点主从备份,水平扩展等问题。在这里就不详细介绍了。

    在Kubernetes中还有许多与externalIPs类似的非常用功能,有些甚至是使用Annotation来进行配置,将来有机会再进一步分享。

    最后插播下广告,为了实现私有环境下的Kubernetes集群自动化部署和运维,我们为Archon系统增加了PXE管理物理机的支持,相应的配置案例在这里。如果使用过程中有任何问题,欢迎跟我们联系。

    最新回复(0)