内容简介:在说说我的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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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》 这本书的介绍吧!