内容简介:在说说我的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模式通用,不过
毕竟,将系统的可靠性依赖于免费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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。