新搭建的 Kubernetes 集群如何承接外部访问的流量,是刚上手 Kubernetes 时常常会遇到的问题。 在公有云上,官方给出了比较直接的答案,使用 LoadBalancer 类型的 Service,利用公有云提供的负载均衡服务来承接流量,同时在多台服务器之间进行负载均衡。
而在私有环境中,如何正确的将外部流量引入到集群内部,却暂时没有标准的做法。 本文将介绍一种基于 IPVS 来承接流量并实现负载均衡的方法,供大家参考。在阅读本文前建议先了解文中相关基础知识点,推荐阅读下「浅析从外部访问 Kubernetes 集群中应用的几种方式」一文。
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 集群当中。搭建过程这里不详细介绍,大家可以参考相关文档,比如:「和我一步步部署 kubernetes 集群」。
所有服务器在 172.17.8.0/24 这个网段中,服务的 VIP 我们设定为 172.17.8.201。整体架构如下图所示:
接下来让我们来配置 IPVS 和 Kubernetes。
使用 externalIPs 暴露 Kubernetes Service
首先在集群内部运行 2 个 nginx Pod 用作演示。
1 | $ kubectl run nginx --image=nginx --replicas=2 |
再将它暴露为 Service,同时设定 externalIPs 字段
1 | $ kubectl expose deployment nginx --port 80 --external-ip 172.17.8.201 |
查看 IPtables 配置,确认对应的 IPtables 规则已经被加入。
1 | $ sudo iptables -t nat -L KUBE-SERVICES -n |
配置 IPVS 实现流量转发
首先在 IPVS 服务器上,打开 ipv4_forward。
1 | $ sudo sysctl -w net.ipv4.ip_forward=1 |
接下来加载 IPVS 内核模块。
1 | $ sudo modprobe ip_vs |
将 VIP 绑定在网卡上。
1 | $ sudo ifconfig eth0:0 172.17.8.201 netmask 255.255.255.0 broadcast 172.17.8.255 |
再使用 ipvsadm 来配置 IPVS,这里我们直接使用 Docker 镜像,避免和特定发行版绑定。
1 | $ docker run --privileged -it --rm --net host luizbafilho/ipvsadm |
可以看到,我们成功建立了从 VIP 到后端服务器的转发。
验证转发效果
首先使用 curl 来测试是否能够正常访问 Nginx 服务。
1 | $ curl http://172.17.8.201 |
接下来在 172.17.8.11 上抓包来确认 IPVS 的工作情况。
1 | $ sudo tcpdump -i any port 80 |
可以看到,由客户端 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 来进行配置,将来有机会再进一步分享。
来源:极术
原文:http://t.cn/RX8vzvC
题图:来自谷歌图片搜索
版权:本文版权归原作者所有