新搭建的kubernetes集群如何承接外部访问的流量,是刚上手kubernetes时常常会遇到的问题。在公有云上,官方给出了比较直接的答案,使用<code>loadbalancer</code>类型的service,利用公有云提供的负载均衡服务来承接流量,同时在多台服务器之间进行负载均衡。而在私有环境中,如何正确的将外部流量引入到集群内部,却暂时没有标准的做法。本文将介绍一种基于ipvs来承接流量并实现负载均衡的方法,供大家参考。
在service的spec中,<code>externalips</code>字段平常鲜有人提到,当把ip地址填入这个字段后,<code>kube-proxy</code>会增加对应的<code>iptables</code>规则,当有以对应ip为目标的流量发送到node节点时,<code>iptables</code>将进行nat,将流量转发到对应的服务上。一般情况下,很少会遇到服务器接受非自身绑定ip流量的情况,所以<code>externalips</code>不常被使用,但配合网络层的其他工具,它可以实现给service绑定外部ip的效果。
今天我们将使用<code>externalips</code>配合ipvs的dr(direct routing)模式实现将外部流量引入到集群内部,同时实现负载均衡。
为了演示,我们搭建了4台服务器组成的集群。一台服务器运行ipvs,扮演负载均衡器的作用,一台服务器运行kubernetes master组件,其他两台服务器作为node加入到kubernetes集群当中。搭建过程这里不详细介绍,大家可以参考相关的文档。
所有服务器在<code>172.17.8.0/24</code>这个网段中。服务的vip我们设定为<code>172.17.8.201</code>。整体架构如下图所示:

接下来让我们来配置ipvs和kubernetes。
首先在集群内部运行2个nginx pod用作演示。
再将它暴露为service,同时设定<code>externalips</code>字段
查看<code>iptables</code>配置,确认对应的<code>iptables</code>规则已经被加入。
首先在ipvs服务器上,打开<code>ipv4_forward</code>。
接下来加载ipvs内核模块。
将vip绑定在网卡上。
再使用<code>ipvsadm</code>来配置ipvs,这里我们直接使用docker镜像,避免和特定发行版绑定。
可以看到,我们成功建立了从vip到后端服务器的转发。
首先使用<code>curl</code>来测试是否能够正常访问nginx服务。
接下来在<code>172.17.8.11</code>上抓包来确认ipvs的工作情况。
可以看到,由客户端<code>172.17.8.1</code>发送给<code>172.17.8.201</code>的封包,经过ipvs的中转发送给了<code>172.17.8.11</code>这台服务器,并经过nat后发送给了<code>10.2.0.3</code>这个pod。返回的封包不经过ipvs服务器直接从<code>172.17.8.11</code>发送给了<code>172.17.8.1</code>。说明ipvs的dr模式工作正常。重复多次测试可以看到流量分别从<code>172.17.8.11</code>和<code>172.17.8.12</code>进入,再分发给不同的pod,
说明负载均衡工作正常。
与传统的ipvs dr模式配置不同的是,我们并未在承接流量的服务器上执行绑定vip,再关闭arp的操作。那是因为对vip的处理直接发生在iptables上,我们无需在服务器上运行程序来承接流量,iptables会将流量转发到对应的pod上。
使用这种方法来承接流量,仅需要配置<code>externalips</code>为vip即可,无需对服务器做任何特殊的设置,使用起来相当方便。
在本文中演示了使用ipvs配合externalips实现将外部流量导入到kubernetes集群中,并实现负载均衡的方法。希望可以帮助大家理解ipvs和externalips的工作原理,以便在恰当的场景下合理使用这两项技术解决问题。实际部署时,还需要考虑后台服务器可用性检查,ipvs节点主从备份,水平扩展等问题。在这里就不详细介绍了。
在kubernetes中还有许多与externalips类似的非常用功能,有些甚至是使用annotation来进行配置,将来有机会再进一步分享。