Kubernetes / Linux Note / 运维笔记

Kubernetes 负载均衡之 Metallb

Einic Yeo · 3月16日 · 2020年 · · ·

对于负载均衡,我们有很多种办法。

负载均衡实际上包含了两个方面:健康探测以及流量分担。如果我们不能健康探测而将流量错误地分到宕机上,会导致流量黑洞。

首先最豪华的解决方案就是硬件负载均衡器,但是一般我们买不起。

其次是路由器 NAT Pool 地址池转换,不过这种不靠谱,因为这种就是简单地将流量分发到服务器上,万一服务器掉线了需要人工去改地址池,也就是缺少健康探测的功能。

我们也可以通过 ipvs 找一台服务器来进行负载均衡,这也是 K8s 集群内部的负载均衡办法,但是这样还是给转发的那台机器带来不必要的负担。

最后一种办法是在路由器上配置等价路由,由路由器进行负载均衡,这样其实和 NAT Pool 缺点是一样的,不过,我们有大杀器——动态路由协议可以帮我们搞定这个问题。

所以我们最后实现了这么一种迂回的办法,就是让机器发布路由信息到路由器上,然后由路由器选择机器进行转发,同时每台机器也及时监控其他机器,一旦发现宕机,则更新路由信息,避免路由器将流量转发到宕机上。

理解 MetalLB 的原理需要对 K8s 控制原理以及计算机网络有着比较深入的理解。但理解了之后,配置的东西其实相当简单。

一、Load Balancer 原理

如果我们使用 GKE、AWS 等公有云,那么一般来说我们给 Service 的 Type 写成 LoadBalancer,云服务厂商就会分配一个 Extern版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!al IP 给我们的 Service,我们只需要访问这个 External IP,其内部就能自动均衡我们的流量到各个实例上。然而作为穷鬼的我们,没有金钱享受如此高端的服务,开源版 Kubernetes 是不会给我们的 LoadBalancer Service 分配 External IP 的。难道穷鬼就不配用负载均衡了吗!!

幸好,即使没有高端的负载均衡器,我们也有开源社区的支持。metallb 就是一款开源的 K8s 负载均衡控制器,只要装上,我们的 Service 就可以拿到 IP 了。如果你对 K8s 已经比较熟悉,那么就知道,所谓 LoadBalancer Service 无非也是一种资源,只是我们缺少一个合适的控制器来为其分配 IP 而已。那么很显然,我们只要装一个分配器,就能得到一个 IP。但是,这个 IP 从哪版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!来?显然只能我们手动分配一段 IP 池让他随便分了。然而其他电脑怎么知道这个 IP 池就是我们的服务所在?版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!如果你熟悉计算机网络,可能会想到 BGP、OSPF 等路由协议。只要在分配好 IP 之后,把这个 IP 路由信息广播出去,那么其他电脑就能知道这个 IP 在哪里。

最简单的,我们可以在服务器的内部子网里找没用的 IP,然后等其他电脑访问这个 IP 的时候,我想办法回应一个 ARP 包,其他电脑就知道这个 IP 在哪里可以通信了,尽管这个 IP 其实没有绑定到任何网卡上,可能只是 iptables 里的一条记录。

然而,通过 ARP 广播的方式局限性非常大,版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!分配的 IP 只能和服务器其他 IP 位于同一子网,但其实对于我们这种小型集群已经够了,但是这不够 geek!有没有高端一点的办法?

有!那就是 BGP。BGP 的原理比较复杂,简单来说就是运行 BGP 的设备之间可以交换路由信息,我们可以将自己的 IP 段通过 BGP 协议告诉其他设备,这样其他设备就能正确的路由数据包到服务器上了。BGP 需要路由器的支持,好在我们的路由器是支持的。BGP 尽管更复杂了一些,但是在 IP 段的选取上有更大的灵活性。尽管负载均衡器原理十分复杂,配置却很简单。

二、安装 metallb 控制器

请根据自己的需要选择对应的版本。

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

三、配置路由器

在配置控制器之前,我们需要配置路由器的 BGP 功能,简单来说就是给路由自己分配一个 AS 号,然后给服务器分配一个 AS 号就可以了,然后声明邻居,使路由器能从服务器获取 BGP 信息。AS 号和 IP 地址一样,也是有私有段的,我们用的就是私有的 AS 号。(注:此处路由器型号为华为 AR-101S,其他路由器请参考配置手册配置 BGP 功能)

路由器的 AS 号是 65315,集群 AS 号是 65199。

[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

到这里路由器就配置完了。

四、配置 metallb 控制器

版权声明:本文遵循 CC 4.0 BY-SA 版权协议,若要转载请务必附上原文出处链接及本声明,谢谢合作!接应用下面的 ConfigMap:

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:

$ 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 路由表:

<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?

可以看到路由器已经收到来自集群的 BGP 信息。

然后检查路由器路由表,是否有多个下一跳:

<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

针对 192.168.15.1,路由表被应用了多个下一跳,因此可以负载均衡。

最后查看 FIB 转发表:

<Huawei>display fib
Route Flags: G - Gateway Route, H - Host Route,    U - Up Route
             S - Static Route,  D - Dynamic Route, B - Black Hole Route
             L - Vlink Route
--------------------------------------------------------------------------------
 FIB Table:
 Total number of Routes : 15

Destination/Mask   Nexthop         Flag  TimeStamp     Interface      TunnelID
192.168.15.1/32    192.168.1.110   DGHU  t[5340582]    Vlanif1        0x0
192.168.15.1/32    192.168.1.111   DGHU  t[5340582]    Vlanif1        0x0
192.168.15.1/32    192.168.1.114   DGHU  t[5340582]    Vlanif1        0x0
192.168.15.1/32    192.168.1.115   DGHU  t[5340582]    Vlanif1        0x0
222.200.180.255/32 127.0.0.1       HU    t[611645]     InLoop0        0x0
222.200.180.45/32  127.0.0.1       HU    t[611645]     InLoop0        0x0
192.168.1.255/32   127.0.0.1       HU    t[201]        InLoop0        0x0
192.168.1.1/32     127.0.0.1       HU    t[201]        InLoop0        0x0
255.255.255.255/32 127.0.0.1       HU    t[79]         InLoop0        0x0
127.255.255.255/32 127.0.0.1       HU    t[79]         InLoop0        0x0
127.0.0.1/32       127.0.0.1       HU    t[79]         InLoop0        0x0
127.0.0.0/8        127.0.0.1       U     t[79]         InLoop0        0x0
192.168.1.0/24     192.168.1.1     U     t[201]        Vlanif1        0x0
222.200.180.0/24   222.200.180.45  U     t[611645]     GE0/0/4        0x0
0.0.0.0/0          222.200.180.254 GSU   t[611645]     GE0/0/4        0x0

可以看到路由器在路由表的指导下,为 192.168.15.1 分配了多个下一跳。

1 条回应
  1. rantrism2022-8-8 · 11:05

    您好~我是腾讯云开发者社区运营,关注了您分享的技术文章,觉得内容很棒,我们诚挚邀请您加入腾讯云自媒体分享计划。完整福利和申请地址请见:https://cloud.tencent.com/developer/support-plan
    作者申请此计划后将作者的文章进行搬迁同步到社区的专栏下,你只需要简单填写一下表单申请即可,我们会给作者提供包括流量、云服务器等,另外还有些周边礼物。