1. Blog
  2. Golang
  3. kubernetes
  4. Rust
  5. 关于作者

metallb 实现浅析

metallb 是一个 kubernetes service loadlbalancer 的 “裸金属” 实现, 即相对于“cloud provider”的实现。

与 metallb 相似的产品还有 openelb,oepnelb 是 qingcloud 开源的 loadbalancer 方案。 与 metallb 相同,支持 arp 和 bgp 两种方式。也均支持 ECMP 等价路由进行负载均衡。

简介

实现了本地 kubernetes 使用 LoadBalancer,load balancer 最大用途为允许 service 分配独立的集群外 IP。对于不同的业务来说,业务之间使用独立的 IP 以减少干扰。

相比于使用 NodePort 使用自定义,独占的 IP 用起来更“bare metal”,对于一个对外的 web 服务来说,总是希望使用 80 端口,而不是 300080。

相比于使用 NodePort,若需要实现上述场景,则需要配合外部的 lb 使用,并且还增加了配置 externalIP+PORT ->internalIP+NodePort,这非常的不 cloud native。

metallb 还支持多个 service 共享一个地址以节约 IP 地址, 因为这些 IP 可能是昂贵的公网。相比独占 IP,共享 IP 的模式会受到一些限制。

metallb 支持 L2 和 BGP 方式进行 IP 通告,metallb 在 kubernetes 上监听 NodePort 类型 service,按照配置对其进行 Internet IP 或者 ethernet IP。

项目地址: github metallb

此外,metallb operator 尚在开发中。

目前该项目正在准备申请 CNCF Sandbox 进入孵化。

安装

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/manifests/metallb.yaml

配置

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/manifests/example-layer2-config.yaml

metallb 从 configmap 读取配置,运行时挂载进入 pod 内,下面是一个 layer2 的示例配置。

address-pools:
  - name: my-ip-space
    protocol: layer2
    addresses:
      - 192.168.1.240/28

非常的简单易懂:定义了一个名字为 my-ip-space 的 IP 池,该 IP 池是 layer2 方式使用的,IP 池范围为 192.168.1.240/28,共计 16 个 IP 。

其中需要注意的字段为: address-pools[].auto-assign ,该字段默认为 true。表示默认从 IP 池中自动分配 IP

详细配置参考:

manifests/example-config.yaml

运行时

metallb 由两部分组成:

实现

metallb 目前提供如下负载均衡方式:

L2

metallb 实现 L2 负载均衡的核心比较简单,仅使用到了 IPv4 ARP 协议以及 IPV6 的 NDP 协议进行 2 层发现。 2 层发现的用于将流量导入到一个节点后进入 iptables 交由 kube-proxy 等处理。 所以 metallb 的 L2 实现上没有特别复杂的逻辑。

metallb controller 为 loadbalancer 类型服务从 IP 池分配一个 loadbalancer IP, speakers 在 ready 的 node 中选择一个 node 以提供 IP 广播。 对于需要广播的 IP,执行 SetBalancer

speaker 会在该 node 上监听 ARP 请求 arp.go#L70 以及 NDP 请求ndp.go#L97, 并对以及设置的 Loadbalancer IP 进行回应。

举例: 若服务 A 设置的 LoadBalancer IP 为 10.0.1.2, 当有请求 10.0.1.2 时, metallb speaker 特定的一个节点会对 arp 询问进行回应, 后该请求数据包进入该节点,后续处理交由 kube-proxy 或者 kube-router 处理。

要完整了解 metallb 下的数据包流转,就还需要了解 kube-proxy 中对 loadbalancer 类型 service 的处理。kube-proxy 的详细实现逻辑在这里不做讨论。

举例:若服务 default/nginx 设置了 LoadBalancer IP 为 172.16.13.204 在基于 iptables 的 kube-proxy 下会产生如下规则:

-A KUBE-SERVICES -d 172.16.13.204/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-SVC-4N57TFCL4MD7ZTDA
...
-A KUBE-SVC-4N57TFCL4MD7ZTDA -j KUBE-SEP-5HQLFPQD5PY6AK3H
...
-A KUBE-SEP-5HQLFPQD5PY6AK3H -p tcp -m tcp -j DNAT --to-destination 10.59.48.237:80

更多信息参考: Type LoadBalancer

待讨论:

  1. 源地址保持与负载均衡可用性,参考TrafficPolicies/Layer2

BGP

metallb BGP 实现上是在每个 node 上有 IBGP,会配置一个外部 BGP Peer,将到 LoadBalancer 的 IP 的路由通过该 peer 播报出去。

后续流量经过路由转发会被路由至特定的节点,后进入 kube-proxy 处理。