Kubernetes 负载均衡器解决方案 MetalLB实践

Kubernetes 负载均衡解决方案 MetalLB实践

MetalLB 是一个用于在 Kubernetes 集群中提供外部 IP 地址的负载均衡器实现。

准备工作

1. 安装需知

安装 MetalLB 有一些前置条件:

  • Kubernetesv1.13.0 或者更新的版本

  • 集群中的 CNI 要能兼容 MetalLB,最新的兼容性参考NETWORK ADDON COMPATIBILITY

    Network addonCompatible
    AntreaYes (Tested on version 1.4 and 1.5)
    CalicoMostly (see known issues)
    CanalYes
    CiliumYes
    FlannelYes
    Kube-ovnYes
    Kube-routerMostly (see known issues)
    Weave NetMostly (see known issues)

    备注:

    常见的 Flannel、Cilium 等都是兼容的,Calico 的话大部分情况都兼容,BGP 模式下需要额外处理。因为 BGP 单 session 的限制,如果 CNI 插件为 Calico ,同时 Calico 也是使用的 BGP 模式,就会有冲突从而导致 MetalLB 无法正常工作。

  • 提供一些 IPv4 地址给 MetalLB 用于分配。

  • 当使用 BGP 操作模式时,你将需要一个或多个能够支持 BGP 协议的路由器。

  • L2 模式下需要各个节点间 7946 端口(TCP & UDP)需要互通。

最新信息参考:requirements

2. 本文部署的环境

确保你的 Kubernetes 集群已经部署并且运行正常。

root@master1:~# kubectl get node -o wide
NAME      STATUS   ROLES           AGE     VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE           KERNEL-VERSION     CONTAINER-RUNTIME
master1   Ready    control-plane   2d19h   v1.28.2   192.168.0.61   <none>        Ubuntu 24.04 LTS   6.8.0-36-generic   containerd://1.7.12
node1     Ready    <none>          2d19h   v1.28.2   192.168.0.62   <none>        Ubuntu 24.04 LTS   6.8.0-36-generic   containerd://1.7.12
node2     Ready    <none>          2d19h   v1.28.2   192.168.0.63   <none>        Ubuntu 24.04 LTS   6.8.0-36-generic   containerd://1.7.12

CNI插件及版本信息:

root@master1:~# calicoctl version
Client Version:    v3.28.0
Git commit:        413e6f559
Cluster Version:   v3.28.0
Cluster Type:      typha,kdd,k8s,operator,bgp,kubeadm

# calico使用bgp模式
root@master1:~# calicoctl node status
Calico process is running.

IPv4 BGP status
+--------------+-------------------+-------+----------+-------------+
| PEER ADDRESS |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+--------------+-------------------+-------+----------+-------------+
| 192.168.0.62 | node-to-node mesh | up    | 01:33:35 | Established |
| 192.168.0.63 | node-to-node mesh | up    | 02:48:04 | Established |
+--------------+-------------------+-------+----------+-------------+

IPv6 BGP status

root@master1:~# calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE   VXLANMODE     DISABLED   DISABLEBGPEXPORT   SELECTOR
default-ipv4-ippool   10.244.0.0/16   true   Never      CrossSubnet   false      false              all()

root@master1:~# kubectl get pod -n calico-system
NAME                                      READY   STATUS    RESTARTS         AGE
calico-kube-controllers-b7fb9d96c-pbf9s   1/1     Running   3 (80m ago)      4d18h
calico-node-gdsjw                         1/1     Running   30 (2m32s ago)   4d18h
calico-node-hvqg4                         1/1     Running   3 (80m ago)      4d18h
calico-node-rj9dd                         1/1     Running   3 (80m ago)      4d17h
calico-typha-55ccdf44bf-v2zmm             1/1     Running   3 (80m ago)      4d18h
calico-typha-55ccdf44bf-w5l8w             1/1     Running   3 (80m ago)      4d18h
csi-node-driver-bqvb7                     2/2     Running   6 (80m ago)      4d18h
csi-node-driver-cw59h                     2/2     Running   6 (80m ago)      4d18h
csi-node-driver-hbw2n                     2/2     Running   6 (80m ago)      4d18h

概念原理说明

1. Layer2模式

该部分的官方文档请参考:[layer2模式](https://metallb.universe.tf/concepts/layer2/)

以下时摘取部分进行翻译:

在 Layer 2 模式下,一个节点承担起向本地网络广告服务的责任。从网络的角度来看,这台机器的网络接口上似乎分配了多个 IP 地址。

在底层,MetalLB 响应 IPv4 服务的 ARP 请求和 IPv6 服务的 NDP 请求。

Layer 2 模式的主要优势是其普遍性:它可以在任何以太网网络上工作,无需特殊硬件,甚至不需要高级路由器。

负载均衡行为

在 Layer 2 模式下,所有针对服务 IP 的流量都会转发到一个节点,然后kube-proxy 会将流量分发到所有的服务 pod。

从这个意义上讲,Layer 2 并没有实现一个负载均衡器,而是实现了一种故障转移机制,以便在当前主节点由于某种原因失败时,其他节点可以接管。

如果主节点由于某种原因失败,故障转移是自动的:使用 memberlist 检测到失败节点,此时新节点接管失败节点的 IP 地址。

局限性

Layer 2 模式有两个主要限制需要注意:单节点瓶颈和潜在的故障转移速度慢。

单节点瓶颈

在 Layer 2 模式下,一个通过选举产生的主节点接收所有服务 IP 的流量。这意味着服务的入口带宽被限制在单个节点的带宽范围内。这是使用 ARP 和 NDP 引导流量的一个根本性限制。

潜在的故障转移速度慢

在故障转移方面,MetalLB 也实现了自动故障转移。目前的机制是通过 memberlist 这个基于 gossip 协议的成员和故障检测的库,其他节点检测到 Leader 故障后自动重新选举出新 Leader,新的 Leader 自动接管所有 ExternalIP 并发送大量二层数据包来通知客户端(也就是区域网中的其他节点) ExternalIP 的 MAC 地址变化。

根据官网文档描述,大部分主流操作系统的现代版本(Windows、Mac、Linux)都正确实现了 Layer 2 故障转移,问题只会出现在较旧或不常见的操作系统上。故障转移正常情况下会在几秒内完成,一般不会超过 10 秒。在更新完成前 ExternalIP 会无法访问。

L2 主节点选举的工作原理

给定负载均衡器 IP 的“主节点”(将要广播 IP 的节点)的选举是无状态的,其工作方式如下:

  1. 每个 speaker 收集给定 IP 的潜在广播者列表,考虑活跃的 speaker、外部流量策略、活跃的端点、节点选择器等因素。
  2. 每个 speaker 都进行相同的计算:获取“节点+VIP”元素的哈希值排序列表,并在自己是该列表的第一个条目时宣布服务。

2. BGP模式

该部分的官方文档请参考:bgp模式

在BGP模式下,集群中的每个节点都会与你的网络路由器建立BGP对等会话,并利用这个对等会话来通告集群外部服务的IP地址。

假设你的路由器配置支持多路径,这就能实现真正的负载均衡:MetalLB发布的路由彼此等价,除了它们的下一跳(nexthop)不同。这意味着路由器会同时使用所有下一跳,并在这之间进行负载均衡。

当数据包到达节点后,kube-proxy负责最后一跳的流量路由,将数据包定向到服务中特定的一个Pod上。

负载均衡行为

负载均衡的具体行为取决于你使用的具体路由器型号和配置,但通常的行为是基于包哈希值,按连接进行负载均衡。“按连接”指的是单个TCP或UDP会话的所有数据包都将被导向集群中的单一机器。流量的分发仅发生在不同的连接间,而不是在一个连接内的数据包之间。

将单个连接的数据包分散到多个集群节点会导致以下问题:

  • 将单个连接分散到多条路径上会导致线路上的数据包重排序,这对终端主机的性能影响巨大。

  • Kubernetes内部的节点间流量路由并不保证一致性。这意味着两个不同的节点可能会将同一连接的数据包路由到不同的Pod,导致连接失败。

局限性

BGP 模式最大的弊端就是不能优雅的处理节点下线。当集群中某个节点下线时,所有客户端对这个节点的连接都会被主动断开。

客户端一般会出现一个 Connection reset by peer 错误

同时由于是对每个数据包基于 hash 值进行负载均衡,因此对后端节点数是非常敏感的,这也是 BGP 的一个优点,故障转移非常快。

正因为 BGP 故障转移很快,反而引发了一个 BGP 模式的最大缺点:由于 BGP 会对每个数据包做负载均衡,在主机发生故障时会快速切换到新的主机上,从而引发节点变动时同一连接的不同数据包可能会发送到不同主机上导致网络导致的网络重排问题

比如第一个包转发到节点 A,然后处理第二个包时添加或故障了一个节点,按照新的节点数进行负载均衡计算,可能第二个数据包就被分到节点 B 了,节点 B 很明显是不能正确处理这个数据包的。

对客户端来说就是这次请求直接失败了。

解决该弊端的方法没有太理想的解决办法,只能尽量采取一些优化手段:

  • BGP路由器配置使用更稳定的ECMP哈希算法。比如“弹性ECMP”或“弹性LAG”。使用这样的算法极大地减少了后端节点更改时受影响的连接。
  • 将你的服务部署固定到特定的节点上,尽量少的增删节点。
  • 在流量“低谷期”进行服务部署的变更。
  • 将每个逻辑服务拆分为两个具有不同IP的Kubernetes服务,并借助DNS优雅地将用户流量从一个服务迁移到另一个服务。
  • 在客户端添加透明的重试逻辑,以优雅地从突然的断开中恢复。如果客户端是如移动应用或富单页Web应用这类应用,这种方法尤其有效。
  • 将你的服务置于入口控制器(ingress controller)之后。入口控制器本身可以使用MetalLB来接收流量,但在BGP和你的服务之间有一个有状态的层意味着你可以更改服务而不必担心。你只需要在更改入口控制器本身的部署时小心(例如,当增加更多的NGINX Pod来扩展规模时)。
  • 接受偶尔会有连接重置的爆发。对于低可用性的内部服务而言,这可能是可接受的现状。

部署 MetalLB

官方提供了好几种安装方式,yaml、helm、operator 等,这里使用 yaml 方式安装。

如果kube-proxy使用的是IPVS模式,在v1.14.2版本之后,需要启用strict ARP mode。

root@master1:~# kubectl edit configmap -n kube-system kube-proxy
...
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: true   # 启用strictARP
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    logging:
      flushFrequency: 0
      options:
        json:
          infoBufferSize: "0"
      verbosity: 0
    metricsBindAddress: ""
    mode: "ipvs"      # kube-proxy模式,默认为iptables
    nodePortAddresses: null
    oomScoreAdj: null
...

# 重启kube-proxy生效
kubectl rollout restart daemonset/kube-proxy -n kube-system

说明:

kube-proxy默认使用的是iptables转发模式,在大规模集群中,建议改为ipvs。如果当前转发模式是ipvs,启用严格的 ARP。

1. 创建 MetalLB 命名空间

kubectl create namespace metallb-system

2. 使用Manifest安装MetalLB

MetalLB 提供了一组清单文件来部署所需的组,使用如下命令部署:

curl https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml -O
kubectl apply -f metallb-native.yaml

查询官网文档获取最新的安装命令。

3. 验证安装

root@master1:~# kubectl get pods -n metallb-system
NAME                          READY   STATUS    RESTARTS      AGE
controller-56bb48dcd4-pp4w4   1/1     Running   2 (60m ago)   47h
speaker-4kfhv                 1/1     Running   1 (60m ago)   43h
speaker-5b5sq                 1/1     Running   7 (60m ago)   47h
speaker-wctd6                 1/1     Running   7 (60m ago)   47h

4. 配置 MetalLB

MetalLB 支持两种操作模式:Layer 2 模式和 BGP 模式。因为 BGP 对路由器有要求,POC测试时建议使用 Layer2 模式。

Layer2模式配置

Layer 2 模式是最简单的配置方式:在许多情况下,你不需要任何特定协议的配置,只需要 IP 地址。

Layer 2 模式不需要将 IP 绑定到你的工作节点的网络接口上。它通过直接响应本地网络上的 ARP 请求,向客户端提供机器的 MAC 地址来工作。

Layer2模式配置,首先创建一个IPAddressPool资源对象:

root@master1:~/metallb# cat ip-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.0.240-192.168.0.250 #分配给LB的IP池

备注

  1. IP地址池与集群IP位于同一个网段。
  2. 多个实例IP地址池可以共存,并且可以分配IPV4和IPV6地址。

应用创建资源:

kubectl apply -f ip-pool.yaml

创建一个广播声明,关联上面的 IP 池对象:

root@master1:~/metallb# cat advertise.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2adver
  namespace: metallb-system
spec:
  ipAddressPools:
    - ip-pool

应用创建资源:

kubectl apply -f advertise.yaml

说明:

如果不设置关联到 IPAdressPool,L2Advertisement 默认会关联所有可用的 IPAdressPool。

BGP模式配置

本文使用Layer2模式测试,后续补充BGP模式的POC验证。关于使用配置可以参考:https://metallb.universe.tf/configuration/#bgp-configuration

高级配置

Metal LB支持一些高级配置用于特殊的需求场景,详见官方文档:

  1. 区分不同的IP地址池:https://metallb.universe.tf/configuration/_advanced_ipaddresspool_configuration/#controlling-automatic-address-allocation

  2. 将IP地址池分配给指定的命名空间和服务:https://metallb.universe.tf/configuration/_advanced_ipaddresspool_configuration/#reduce-scope-of-address-allocation-to-specific-namespace-and-service

Layer2模式demo应用示例

1. 创建一个示例应用

为了验证 MetalLB 的配置是否正确,你可以创建一个简单的 Nginx 服务。

创建一个 nginx-deployment.yaml 文件,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

应用创建资源:

kubectl apply -f nginx-deployment.yaml

2. 暴露 Nginx 服务

创建一个 nginx-service.yaml 文件,内容如下:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: LoadBalancer

应用此服务:

kubectl apply -f nginx-service.yaml

3. 验证服务

检查服务的外部 IP 地址是否已分配:

kubectl get svc nginx-service

你应该会看到类似以下的输出:

root@master1:~/metallb# kubectl get svc nginx-service
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)        AGE
nginx-service   LoadBalancer   10.101.212.243   192.168.0.240   80:30981/TCP   2d16h

在浏览器中访问 http://<EXTERNAL-IP>,例如 http://192.168.0.240,应该可以看到 Nginx 的默认页面。

或者使用curl测试:

root@master1:~/metallb# curl http://192.168.0.240
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

总结

1. MetalLB工作流程

MetalLB 做的工作可以分为两个部分:

  1. 地址分配:当创建 LoadBalancer Service 时,MetalLB 会为其分配 IP 地址。这个 IP 地址是从预先配置的 IP 地址库获取的。当 Service 删除后,已分配的 IP 地址会重新回到地址库。使用Controller实现地址分配,以 Deployment方式运行,用于监听 Service 的变更,分配/回收 IP 地址。

  2. 对外广播:分配了 IP 地址之后,需要让集群外的网络知道这个地址的存在。由Speaker实现地址对外广播,以 DaemonSet 方式运行,对外广播 Service 的 IP 地址。MetalLB 使用了标准的TCP/IP协议实现:ARP、NDP 或者 BGP。

  • 在 Layer 2 模式,使用 ARP(ipv4)/NDP(ipv6) 协议;
  • 在 BPG 模式,自然是使用 BGP 协议。

ARP(Address Resolution Protocol):是根据IP地址获取物理地址的一个TCP/IP协议。

NDP(neighbor Discovery protocol):ICMPv6的子协议,是IPV6协议体系中一个重要的基础协议,NDP替代了IPV4中的ARP。定义了使用ICMPv6报文实现地址解析,跟踪邻居状态,重复地址检测,路由器发现,以及重定向等功能。

具体的工作流如下:

  • Controller 负责监听 Service 变化并分配或回收 IP。

    当 Service 配置为 LoadBalancer 模式时,从 IP 池分配给到相应的 IP 地址并对该 IP 的生命周期进行管理。

    • 创建 Service 时(或者从非 LoadBalancer 类型修改为 LoadBalancer 类型)时从 IP 池选择一个 IP 并分配,
    • 删除 Service (或者从 LoadBalancer 类型修改为非 LoadBalancer 类型)时回收该 IP 到 IP 池
  • Speaker 则会依据选择的协议进行相应的广播或应答,实现 IP 地址的通信响应

    当业务流量通过 TCP/UDP 协议到达指定的 Node 时,由 Node 上面运行的 Kube-Proxy 组件对流量进行处理,并分发到对应服务的 Pod 上面。

    • 如果是 Layer2 模式 Speaker 就会响应 ARP(ipv4)/NDP(ipv6)请求。
    • 如果是 BGP 模式 Speaker 则发送 BGP 广播,将路由规则同步给 peer。

2. 两种模式的优缺点

Layer2 模式
  • 优点:通用性好,适用于任何网络环境,不需要特殊的硬件。
  • 缺点:单节点瓶颈和故障转移慢

Layer2 模式是一种基础、通用的实现,能用,而且易于使用,没有任何限制,但是局限性比较大。

BGP 模式
  • 优点:使用 BGP 可以在多节点间负载均衡,没有单节点瓶颈,同时故障转移很快。
  • 缺点: 需要支持 BGP 路由协议的软路由或者硬件 路由器设备。

参考资料

  1. MetalLB, bare metal load-balancer for Kubernetes
  2. Metal LB installation
  3. 裸机 Kubernetes 集群负载均衡器: MetalLB 简明教程 - (lixueduan.com)
  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lldhsds

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值