如果我们使用 GKE、AWS 等公有云,那么一般来说我们给 Service 的 Type 写成 LoadBalancer,云服务厂商就会分配一个 External IP 给我们的 Service,我们只需要访问这个 External IP,其内部就能自动均衡我们的流量到各个实例上。然而作为穷鬼的我们,没有金钱享受如此高端的服务,开源版 Kubernetes 是不会给我们的 LoadBalancer Service 分配 External IP 的。难道穷鬼就不配用负载均衡了吗!!
幸好,即使没有高端的负载均衡器,我们也有开源社区的支持。metallb 就是一款开源的 K8s 负载均衡控制器,只要装上,我们的 Service 就可以拿到 IP 了。如果你对 K8s 已经比较熟悉,那么就知道,所谓 LoadBalancer Service 无非也是一种资源,只是我们缺少一个合适的控制器来为其分配 IP 而已。那么很显然,我们只要装一个分配器,就能得到一个 IP。但是,这个 IP 从哪来?显然只能我们手动分配一段 IP 池让他随便分了。然而其他电脑怎么知道这个 IP 池就是我们的服务所在?如果你熟悉计算机网络,可能会想到 BGP、OSPF 等路由协议。只要在分配好 IP 之后,把这个 IP 路由信息广播出去,那么其他电脑就能知道这个 IP 在哪里。
最简单的,我们可以在服务器的内部子网里找没用的 IP,然后等其他电脑访问这个 IP 的时候,我想办法回应一个 ARP 包,其他电脑就知道这个 IP 在哪里可以通信了,尽管这个 IP 其实没有绑定到任何网卡上,可能只是 iptables 里的一条记录。
然而,通过 ARP 广播的方式局限性非常大,分配的 IP 只能和服务器其他 IP 位于同一子网,但其实对于我们这种小型集群已经够了,但是这不够 geek!有没有高端一点的办法?
有!那就是 BGP。BGP 的原理比较复杂,简单来说就是运行 BGP 的设备之间可以交换路由信息,我们可以将自己的 IP 段通过 BGP 协议告诉其他设备,这样其他设备就能正确的路由数据包到服务器上了。BGP 需要路由器的支持,好在我们的路由器是支持的。BGP 尽管更复杂了一些,但是在 IP 段的选取上有更大的灵活性。尽管负载均衡器原理十分复杂,配置却很简单。
在配置控制器之前,我们需要配置路由器的 BGP 功能,简单来说就是给路由自己分配一个 AS 号,然后给服务器分配一个 AS 号就可以了,然后声明邻居,使路由器能从服务器获取 BGP 信息。AS 号和 IP 地址一样,也是有私有段的,我们用的就是私有的 AS 号。(注:此处路由器型号为华为 AR-101S,其他路由器请参考配置手册配置 BGP 功能)
路由器的 AS 号是 65315,集群 AS 号是 65199。
1 2 3 4 5 6 7 8 9 10 11 12 13
[Huawei] bgp 65315 # 打开路由器 BGP 功能,分配 65315 AS 号 [Huawei-bgp] group servers external # 声明外部邻居组 [Huawei-bgp] peer servers as-number 65199 # 声明组 AS 号为 65199 [Huawei-bgp] peer 192.168.1.110 group servers # 声明组内邻居 [Huawei-bgp] peer 192.168.1.111 group servers [Huawei-bgp] peer 192.168.1.113 group servers [Huawei-bgp] peer 192.168.1.114 group servers [Huawei-bgp] peer 192.168.1.115 group servers [Huawei-bgp] peer 192.168.1.116 group servers [Huawei-bgp] peer 192.168.1.117 group servers [Huawei-bgp] peer 192.168.1.118 group servers [Huawei-bgp] peer 192.168.1.119 group servers [Huawei-bgp] maximum load-balancing 4 # 默认情况下,路由只会从学习到的 BGP 路由信息中选取最佳的 1 条写进路由表,而只有路由表中同一目的地址含有多个等价下一条才能实现负载均衡。所以,我们要指示 BGP 将多条路由同时写进路由表,我们的路由器型号最大只支持 4
到这里路由器就配置完了。
配置控制器
直接应用下面的 ConfigMap:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
apiVersion:v1 kind:ConfigMap metadata: namespace:metallb-system name:config data: config:| peers: - peer-address: 192.168.1.1 # 路由器的 IP 地址 peer-asn: 65315 # 路由器的 AS 号 my-asn: 65199 # 集群 AS 号 address-pools: - name: default protocol: bgp addresses: - 192.168.15.0/24 # 希望分配的 IP 地址池,到时候会分配给 Service 的 ExternalIP
检查负载均衡是否生效
首先将一个 Service 改成 LoadBalancer,然后查看是否分配到了 External IP:
1 2 3
$ kubectl get svc traefik-load-balance-service -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE traefik-load-balance-service LoadBalancer 10.97.104.52 192.168.15.1 80:32703/TCP,443:32237/TCP 13h
可以看到确实分配到了一个我们地址池中的 IP。
然后检查路由是否学习到了 BGP 路由表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<Huawei>display bgp routing-table BGP Local router ID is 192.168.1.1 Status codes: * - valid, > - best, d - damped, h - history, i - internal, s - suppressed, S - Stale Origin : i - IGP, e - EGP, ? - incomplete Total Number of Routes: 8 Network NextHop MED LocPrf PrefVal Path/Ogn *> 192.168.15.1/32 192.168.1.110 0 65199? * 192.168.1.111 0 65199? * 192.168.1.114 0 65199? * 192.168.1.115 0 65199? * 192.168.1.116 0 65199? * 192.168.1.117 0 65199? * 192.168.1.118 0 65199? * 192.168.1.119 0 65199?
<Huawei>display ip routing-table Route Flags: R - relay, D - download to fib ------------------------------------------------------------------------------ Routing Tables: Public Destinations : 12 Routes : 15 Destination/Mask Proto Pre Cost Flags NextHop Interface 0.0.0.0/0 Static 60 0 D 222.200.180.254 GigabitEthernet0/0/4 127.0.0.0/8 Direct 0 0 D 127.0.0.1 InLoopBack0 127.0.0.1/32 Direct 0 0 D 127.0.0.1 InLoopBack0 127.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0 192.168.1.0/24 Direct 0 0 D 192.168.1.1 Vlanif1 192.168.1.1/32 Direct 0 0 D 127.0.0.1 Vlanif1 192.168.1.255/32 Direct 0 0 D 127.0.0.1 Vlanif1 192.168.15.1/32 EBGP 255 0 D 192.168.1.110 Vlanif1 EBGP 255 0 D 192.168.1.111 Vlanif1 EBGP 255 0 D 192.168.1.114 Vlanif1 EBGP 255 0 D 192.168.1.115 Vlanif1 222.200.180.0/24 Direct 0 0 D 222.200.180.45 GigabitEthernet0/0/4 222.200.180.45/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/4 222.200.180.255/32 Direct 0 0 D 127.0.0.1 GigabitEthernet0/0/4 255.255.255.255/32 Direct 0 0 D 127.0.0.1 InLoopBack0