穷人的LoadBalancer

栏目: 服务器 · 发布时间: 7年前

内容简介:在说说我的homelab里,伊布介绍了家里的homelab,其中包括了kubernetes集群的信息。这里面伊布比较不满意的是,kubernetes集群没有L4负载均衡,对外暴漏服务时,只能使用nodePort的方式,比较麻烦:必须要记住不同的端口号。前两天去上海kubeCon的时候,看到有人介绍他的树莓派集群,其中L4负载均衡使用的是metalLB,瞬间眼前一亮,这不就是伊布一直想要的东西嘛!

在说说我的homelab里,伊布介绍了家里的homelab,其中包括了kubernetes集群的信息。这里面伊布比较不满意的是,kubernetes集群没有L4负载均衡,对外暴漏服务时,只能使用nodePort的方式,比较麻烦:必须要记住不同的端口号。

前两天去上海kubeCon的时候,看到有人介绍他的树莓派集群,其中L4负载均衡使用的是metalLB,瞬间眼前一亮,这不就是伊布一直想要的东西嘛!

MetalLB 可谓是“穷人的LoadBalancer”。kubernetes本身并没有实现LoadBalancer;如果是云上用户,可以使用云服务商提供的provider;而对于bare metal的用户来说,则可以使用metalLB来达到相同的目的。

metalLB的两个核心特性:

地址分配

metalLB会为用户的load balancer类型service分配IP地址,该IP地址不是凭空产生的,需要用户预先分配。

外部声明

地址分配后还需要通知到网络中的其他主机。metalLB支持两种声明模式:

  • Layer 2模式:ARP/NDP
  • BGP模式

Layer 2 模式

Layer 2模式下,每个service会有集群中的一个node来负责。当服务客户端发起ARP解析的时候,对应的node会响应该ARP请求,之后,该service的流量都会指向该node(看上去该node上有多个地址)。

Layer 2模式并不是真正的负载均衡,因为流量都会先经过1个node后,再通过kube-proxy转给多个end points。如果该node故障,metalLB会迁移 IP到另一个node,并重新发送免费ARP告知客户端迁移。现代操作系统基本都能正确处理免费ARP,因此failover不会产生太大问题。

Layer 2模式更为通用,不需要用户有额外的设备;但由于Layer 2模式使用ARP/ND,地址池分配需要跟客户端在同一子网,地址分配略为繁琐。

BGP模式

BGP模式下,集群中所有node都会跟上联路由器建立BGP连接,并且会告知路由器应该如何转发service的流量。

BGP模式是真正的LoadBalancer。

metalLB部署

安装metalLB比较简单。

kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml

编排文件主要部署2个组件:

metallb-system/controller
metallb-system/speaker

注意,部署后,还需要根据具体的地址通告方式,配置configmap metallb-system/config 。controller会读取该configmap,并reload配置。

下面分别介绍两种模式的部署。

Layer 2模式部署

如下是Layer 2模式加的config,在伊布的环境下,为service分配的地址池是 192.168.0.10-192.168.0.100 。

将下面的编排文件使用kubectl apply到集群上去。

kind: ConfigMap
apiVersion: v1
metadata:
  name: config
  namespace: metallb-system
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.0.10-192.168.0.100

至此,metalLB Layer 2 mode的配置就结束了。来验证下。

$ kubectl get pods nginx-68995d8957-bczhf -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE       
nginx-68995d8957-bczhf   2/2     Running   0          19d   10.244.0.78   ubuntu-1  
$ kubectl get svc
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
nginx   LoadBalancer   10.97.187.100   192.168.0.10   80:32353/TCP   179m

可以看到,svc nginx分配的的外部IP地址是 192.168.0.10 ,这也是伊布的地址池中的第一个IP。浏览器访问 192.168.0.10 ,可以正常显示nginx的页面。

metalLB是怎么做的呢?

先在客户端上看看 192.168.0.10 的ARP地址。

❯❯❯ arp 192.168.0.10
? (192.168.0.10) at 0:c:29:f3:b2:1d on en0 ifscope [ethernet]
❯❯❯ arp ubuntu-1
ubuntu-1.lan (192.168.0.154) at 0:c:29:f3:b2:1d on en0 ifscope [ethernet]

有点意思。 192.168.0.10 的mac地址,和ubuntu-1的地址是一样的。显然,因为nginx pod是运行在ubuntu-1上的,因此当客户端发起ARP请求的时候,ubuntu-1上的speaker会应答该请求,将流量导向ubuntu-1。

去看ubuntu-1的speaker的日志,可以看到一些记录。

{"caller":"arp.go:102","interface":"ens160","ip":"192.168.0.10","msg":"got ARP request for service IP, sending response","responseMAC":"00:0c:29:f3:b2:1d","senderIP":"192.168.0.234","senderMAC":"00:22:6d:57:a2:1c","ts":"2019-06-30T04:31:29.524752775Z"}

那么报文到了ubuntu-1之后呢?伊布们来看看iptables规则。

-A KUBE-SERVICES -d 192.168.0.10/32 -p tcp -m comment --comment "default/nginx: loadbalancer IP" -m tcp --dport 80 -j KUBE-FW-4N57TFCL4MD7ZTDA

-A KUBE-FW-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx: loadbalancer IP" -j KUBE-MARK-MASQ
-A KUBE-FW-4N57TFCL4MD7ZTDA -m comment --comment "default/nginx: loadbalancer IP" -j KUBE-SVC-4N57TFCL4MD7ZTDA

-A KUBE-SVC-4N57TFCL4MD7ZTDA -j KUBE-SEP-HQ2WPKJSGAOND4TJ

-A KUBE-SEP-HQ2WPKJSGAOND4TJ -s 10.244.0.78/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-HQ2WPKJSGAOND4TJ -p tcp -m tcp -j DNAT --to-destination 10.244.0.78:80

是不是似曾相识?对,这些规则,和nodePort类型的service的iptables规则,是类似的。

至此,Layer 2模式的metalLB就可以正常工作了。

BGP模式部署

Layer 2模式通用,不过

作为geeker,不应该满足于

毕竟,将系统的可靠性依赖于免费ARP,不是一种正经的做法。

BGP模式部署,对环境有一定的要求:

得有一个可以运行BGP协议的上联交换机。

在伊布的homelab中,kubernetes的node是hp gen8上运行的虚拟机,从逻辑上来看,可以认为,各个vm是连接到WNDR4300的。因此,只要WNDR4300上可以运行bgp协议,就可以支持BGP模式部署。

伊布的WNDR4300上运行的是openwrt,这是一个完全自主可控的路由器操作系统,生态比较完善,十分推荐。

openwrt上可以运行 quagga 。 quagga 是一个unix平台下的经典路由软件套件,实现了以下路由协议:OSPFv2, OSPFv3, RIP v1 and v2, RIPng and BGP-4。在这里,伊布将使用quagga的bgp功能,来完成metalLB的BGP模式部署。

当然,如果您不想使用openwrt,也可以使用商业路由器,如UBNT ER系列,H3C/HW等厂家的路由器。

openwrt安装quagga

openwrt使用opkg来管理软件包,默认的源在国内使用比较慢,您可以使用ustc的镜像源。

修改 /etc/opkg/distfeeds.conf :

src/gz openwrt_core http://mirrors.ustc.edu.cn/lede/releases/18.06.2/targets/ar71xx/nand/packages
src/gz openwrt_base http://mirrors.ustc.edu.cn/lede/releases/18.06.2/packages/mips_24kc/base
src/gz openwrt_luci http://mirrors.ustc.edu.cn/lede/releases/18.06.2/packages/mips_24kc/luci
src/gz openwrt_packages http://mirrors.ustc.edu.cn/lede/releases/18.06.2/packages/mips_24kc/packages
src/gz openwrt_routing http://mirrors.ustc.edu.cn/lede/releases/18.06.2/packages/mips_24kc/routing
src/gz openwrt_telephony http://mirrors.ustc.edu.cn/lede/releases/18.06.2/packages/mips_24kc/telephony

需要安装 quagga、quagga-zebra、quagga-bgpd,以及用于管理的quagga-watchquagga、quagga-vtysh。

root@OpenWrt:~# opkg install quagga quagga-zebra quagga-bgpd quagga-watchquagga quagga-vtysh

安装好以后,启动quagga,启动后会监听2601、2605、179端口号。

root@OpenWrt:~# /etc/init.d/quagga start
root@OpenWrt:~# netstat -antp|grep LISTEN
tcp        0      0 0.0.0.0:2601            0.0.0.0:*               LISTEN      23173/zebra
tcp        0      0 0.0.0.0:2605            0.0.0.0:*               LISTEN      23178/bgpd
tcp        0      0 0.0.0.0:179             0.0.0.0:*               LISTEN      23178/bgpd

openwrt配置BGP协议

从拓扑上来说,WNDR4300会跟kubernetes上的各个node建立BGP peer对,在这里伊布设置WNDR4300的AS为65000,kubernetes上各个node的AS为65009。

ssh登录到OpenWrt后,使用vtysh命令进入Quagga的命令行。配置如下。

OpenWrt# configure terminal
OpenWrt(config)# router bgp 65000
OpenWrt(config-router)# neighbor 192.168.0.154 remote-as 65009
OpenWrt(config-router)# neighbor 192.168.0.154 description "ubuntu-1"
OpenWrt(config-router)# neighbor 192.168.0.153 remote-as 65009
OpenWrt(config-router)# neighbor 192.168.0.153 description "ubuntu-2"
OpenWrt(config-router)# neighbor 192.168.0.171 remote-as 65009
OpenWrt(config-router)# neighbor 192.168.0.171 description "ubuntu-3"
OpenWrt(config-router)# neighbor 192.168.0.163 remote-as 65009
OpenWrt(config-router)# neighbor 192.168.0.163 description "x1"
OpenWrt(config-router)# neighbor 192.168.0.127 remote-as 65009
OpenWrt(config-router)# neighbor 192.168.0.127 description "x201"

此时,只是配置了WNDR4300的BGP,还需要配置kubernetes上各个node的路由信息。

kubernetes上配置BGP协议

前面伊布已经安装了metalLB的controller和speaker,只是使用的是Layer 2模式。要改为BGP模式,只要修改configmap config就可以了。

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    peers:
    - peer-address: 192.168.0.1
      peer-asn: 65000
      my-asn: 65009
    address-pools:
    - name: default
      protocol: bgp
      addresses:
      #- 192.168.0.10-192.168.0.100
      - 192.168.9.0/24

需要注意的是,伊布重新分配了一个新的网段 192.168.9.0/24 ,而没有使用Layer 2模式的 192.168.0.10-192.168.0.100 。伊布理解这是BGP模式的一个优势,完全解决了Layer 2模式ARP造成的依赖,可以使用更多更灵活的网段。

地址池修改后,svc的地址也必然需要发生变化,不过伊布在实践中发现,controller此时并不会重新分配地址,而只是报了错误,提示用户当前svc的地址不在地址池中。anyway,只要重启controller,就可以重新分配地址了。

看看当前的BGP状态。

OpenWrt# show ip bgp summary
BGP router identifier 192.168.1.4, local AS number 65000
RIB entries 3, using 216 bytes of memory
Peers 5, using 24 KiB of memory

Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd
192.168.0.127   4 65009     651     654        0    0    0 00:25:58        2
192.168.0.153   4 65009    1111    1139        0    0    0 00:26:19        2
192.168.0.154   4 65009     652     664        0    0    0 00:26:17        2
192.168.0.163   4 65009     632     647        0    0    0 00:26:19        2
192.168.0.171   4 65009     648     670        0    0    0 00:26:19        2

可以看到,WNDR4300和kubernetes上的各个node建立了BGP邻居;查看speaker的日志,会看到如下的日志,表示BGP会话已经established了。

struct { Version uint8; ASN16 uint16; HoldTime uint16; RouterID uint32; OptsLen uint8 }{Version:0x4, ASN16:0xfde8, HoldTime:0xb4, RouterID:0xc0a80104, OptsLen:0x1e}
{"caller":"bgp.go:63","event":"sessionUp","localASN":65009,"msg":"BGP session established","peer":"192.168.0.1:179","peerASN":65000,"ts":"2019-06-30T12:54:07.707648249Z"}

controller重启后,为前面svc nginx重新分配的地址为 192.168.9.0 。来看看WNDR4300上的路由表项。

OpenWrt# show ip route
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, P - PIM, A - Babel,
       > - selected route, * - FIB route

K>* 0.0.0.0/0 via 192.168.1.1, eth0.2, src 192.168.1.4
K>* 119.28.4.177/32 via 192.168.1.1, eth0.2
C>* 127.0.0.0/8 is directly connected, lo
C>* 192.0.2.0/24 is directly connected, wg0
C>* 192.168.0.0/24 is directly connected, br-lan
C>* 192.168.1.0/24 is directly connected, eth0.2
B>* 192.168.9.0/32 [20/0] via 192.168.0.153, br-lan, 00:36:46
B>* 192.168.9.1/32 [20/0] via 192.168.0.153, br-lan, 00:36:46

可以看到,最后两条为BGP路由,会将 192.168.9.0 的报文转发到 192.168.0.153 。此时在客户端浏览器上访问 192.168.9.0 ,会显示nginx的页面(客户端的默认路由为WNDR4300的IP地址 192.168.0.1 )。

BGP模式解析

下面来解析下BGP模式。

由于客户端的默认路由是WNDR4300的IP 192.168.0.1 ,因此浏览器访问 192.168.9.0 时,报文会发送给WNDR4300。

在WNDR4300上查BGP路由,Next Hop命中 192.168.0.153 ,WNDR4300将报文转发给 192.168.0.153 。

报文到 192.168.0.153 后,会命中iptables规则,将报文转发给实际Pod的EndPoint,之后的流程就跟一般访问svc类似了。

-A KUBE-SERVICES -d 192.168.9.0/32 -p tcp -m comment --comment "default/nginx: loadbalancer IP" -m tcp --dport 80 -j KUBE-FW-4N57TFCL4MD7ZTDA

可见,报文经路由器转发后,实际仍然是由kubernetes上的一个node进行集群内部的转发的,这一点与Layer 2模式类似。

failover

那么,如果 192.168.0.153 故障了呢?来详细查看下WNDR4300上的bgp路由。

OpenWrt# show ip bgp
BGP table version is 0, local router ID is 192.168.1.4
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
              i internal, r RIB-failure, S Stale, R Removed
Origin codes: i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*  192.168.9.0/32   192.168.0.127                          0 65009 ?
*                   192.168.0.154                          0 65009 ?
*>                  192.168.0.153                          0 65009 ?
*                   192.168.0.163                          0 65009 ?
*                   192.168.0.171                          0 65009 ?
*  192.168.9.1/32   192.168.0.127                          0 65009 ?
*                   192.168.0.154                          0 65009 ?
*>                  192.168.0.153                          0 65009 ?
*                   192.168.0.163                          0 65009 ?
*                   192.168.0.171                          0 65009 ?

可见,实际Next Hop包含了kubernetes所有的node,但当前只使用了一个(即 > 指向的条目);当 192.168.0.153 故障时,BGP会快速切换到另一个Hop,完成故障转移。

总结

本文介绍了MetalLB,并介绍了MetalLB的两种部署模式:Layer 2模式和BGP模式。在实际应用中,如果条件满足,推荐使用BGP模式。

Ref:


以上所述就是小编给大家介绍的《穷人的LoadBalancer》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Ordering Disorder

Ordering Disorder

Khoi Vinh / New Riders Press / 2010-12-03 / USD 29.99

The grid has long been an invaluable tool for creating order out of chaos for designers of all kinds—from city planners to architects to typesetters and graphic artists. In recent years, web designers......一起来看看 《Ordering Disorder》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换