Kubernetes 私有集群负载均衡器终极解决方案 MetalLB ( 贫苦 K8S 用户的 LoadBalancer )

Posted by Mike on 2020-05-08

私有云裸金属架构(这里是相对云上环境来说,不是说无操作系统)上部署的 Kubernetes 集群,通常是无法使用 LoadBalancer 类型的 Service 的。因为 Kubernetes 本身没有为裸机群集提供网络负载均衡器(类型为 LoadBalancer 的服务)的实现。如果你的 Kubernetes 集群没有在公有云的 IaaS 平台(GCP,AWS,Azure …)上运行,则 LoadBalancers 将在创建时无限期地保持 “挂起” 状态,也就是说只有公有云厂商自家的 Kubernetes 支持 LoadBalancer 。

为了从外部访问裸机 Kubernetes 群集,目前只能使用 NodePortIngress 的方法进行服务暴露。前者的缺点是每个暴露的服务需要占用所有节点的某个端口,后者的缺点是仅仅能支持 HTTP 协议。

什么是 MetalLB

MetalLB 是一个负载均衡器,专门解决裸金属 Kubernetes 集群中无法使用 LoadBalancer 类型服务的痛点。MetalLB 使用标准化的路由协议,以便裸金属 Kubernetes 集群上的外部服务也尽可能地工作。即 MetalLB 能够帮助你在裸金属 Kubernetes 集群中创建 LoadBalancer 类型的 Kubernetes 服务,该项目发布于 2017 年底,当前处于 Beta 阶段。

项目地址:https://github.com/danderson/metallb

MetalLB 工作原理

MetalLB 会在 Kubernetes 内运行,监控服务对象的变化,一旦监测到有新的 LoadBalancer 服务运行,并且没有可申请的负载均衡器之后,就会完成地址分配和外部声明两部分的工作。

地址分配

在云环境中,当你请求一个负载均衡器时,云平台会自动分配一个负载均衡器的 IP 地址给你,应用程序通过此 IP 来访问经过负载均衡处理的服务。

使用 MetalLB 时,MetalLB 会自己为用户的 LoadBalancer 类型 Service 分配 IP 地址,当然该 IP 地址不是凭空产生的,需要用户在配置中提供一个 IP 地址池,Metallb 将会在其中选取地址分配给服务。

外部声明

MetalLB 将 IP 分配给某个服务后,它需要对外宣告此 IP 地址,并让外部主机可以路由到此 IP。

MetalLB 支持两种声明模式:Layer 2( ARP / NDP )模式或者 BGP 模式。

  1. Layer 2 模式

在任何以太网环境均可使用该模式。当在第二层工作时,将有一台机器获得 IP 地址(即服务的所有权)。MetalLB 使用标准的地址发现协议(对于 IPv4 是 ARP,对于 IPv6 是 NDP)宣告 IP 地址,使其在本地网路中可达。从 LAN 的角度来看,仅仅是某台机器多配置了一个 IP 地址。

Layer 2 模式下,每个 Service 会有集群中的一个 Node 来负责。服务的入口流量全部经由单个节点,然后该节点的 Kube-Proxy 会把流量再转发给服务的 Pods。也就是说,该模式下 MetalLB 并没有真正提供负载均衡器。尽管如此,MetalLB 提供了故障转移功能,如果持有 IP 的节点出现故障,则默认 10 秒后即发生故障转移,IP 会被分配给其它健康的节点。

Layer 2 模式的优缺点:

  • Layer 2 模式更为通用,不需要用户有额外的设备;

  • Layer 2 模式下存在单点问题,服务的所有入口流量经由单点,其网络带宽可能成为瓶颈;

  • 由于 Layer 2 模式需要 ARP/NDP 客户端配合,当故障转移发生时,MetalLB 会发送 ARP 包来宣告 MAC 地址和 IP 映射关系的变化,地址分配略为繁琐。

  1. BGP 模式

当在第三层工作时,集群中所有机器都和你控制的最接近的路由器建立 BGP 会话,此会话让路由器能学习到如何转发针对 K8S 服务 IP 的数据包。

通过使用 BGP,可以实现真正的跨多节点负载均衡(需要路由器支持 multipath),还可以基于 BGP 的策略机制实现细粒度的流量控制。

具体的负载均衡行为和路由器有关,可保证的共同行为是:每个连接(TCP 或 UDP 会话)的数据包总是路由到同一个节点上。

BGP 模式的优缺点:

  • 不能优雅处理故障转移,当持有服务的节点宕掉后,所有活动连接的客户端将收到 Connection reset by peer ;

  • BGP 路由器对数据包的源 IP、目的 IP、协议类型进行简单的哈希,并依据哈希值决定发给哪个 K8S 节点。问题是 K8S 节点集是不稳定的,一旦(参与 BGP)的节点宕掉,很大部分的活动连接都会因为 rehash 而坏掉。

BGP 模式问题的缓和措施:

  • 将服务绑定到一部分固定的节点上,降低 rehash 的概率。

  • 在流量低的时段改变服务的部署。

  • 客户端添加透明重试逻辑,当发现连接 TCP 层错误时自动重试。

部署 MetalLB

环境要求

根据部署模式不同,MetalLB 可能需要以下环境:

  1. 一个 Kubernetes 集群,运行 Kubernetes 1.13.0 或更高版本。

  2. Kubernetes 集群的网络配置可以与 MetalLB 共存。

  3. 有一些提供给 MetalLB 分发的 IPv4 地址。

  4. 根据部署模式,可能需要一个或多个 BGP 的路由器 。

MetalLB 目前支持网络插件范围

网络插件 兼容性
Calico 部分支持(有附加文档)
Flannel 支持
Kube-router 不支持
Romana 支持(有附加文档)
Weave Net 支持

从 Kubernetes 1.9 开始, Kube-Proxy 除了支持默认的 Iptables 模式之外,还支持更高效的 IPVS 模式。MetalLB 可以在Kubenetes 1.13 或更高版本的 Kube-Proxy 中使用 IPVS 模式。但是,它尚未明确测试,因此风险自负。具体内容可参考:https://github.com/google/metallb/issues/153

安装 MetalLB

安装 MetalLB 一共有两种方法:使用 Kubernetes YAML 文件或使用 Helm 包管理器。

使用 YAML 文件部署

1
2
# 目前 MetalLB 最新版本为 0.8.1
$ kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.8.1/manifests/metallb.yaml

部署完成后,将在 metallb-system 命名空间下将 MetalLB 部署到集群。YAML 文件中主要包含以下一些组件:

  1. metallb-system/controller,这是处理 IP 地址分配的控制器。

  2. metallb-system/speakerdaemonset 这是支持你选择协议以使服务可达的组件。

  3. ControllerSpeakerService Accounts,以及组件需要运行的 RBAC 权限。

通过 YAML 安装文件部署并不包含 MetalLB 配置文件,但 MetalLB 的组件仍能启动,但在你定义和部署 configmap 之前将保持空闲状态 。

使用 Helm 部署

1
$ helm install --name metallb stable/metallb

如果你还不知道什么是 Helm,可以先参考 「Helm 入门指南」 一文。

配置 MetalLB

MetalLB 安装完成后,我们还需要根据具体的地址和通告方式配置名为 metallb-system/config 的 ConfigMap。Controller 会读取该 ConfigMap,并重新加载配置。

通过 Helm 安装时,MetalLB 读取的 ConfigMap 名为 metallb-config 。

配置 MetalLB 为二层模式

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

第二层模式不要求将 IP 绑定到工作节点的网络接口。它的工作原理是直接响应本地网络上的 ARP 请求,将机器的 MAC 地址提供给客户端。

下面我们来看一个实际例子,我们将配置一个由 MetalLB 二层模式控制的外部 IP 段为 192.168.1.240 - 192.168.1.250。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat MetalLB-Layer2-Config.yaml

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

注意:这里的 IP 地址范围需要跟集群实际情况相对应。

首先,我们使用 kubectl apply -f MetalLB-Layer2-Config.yaml 命令使配置生效。如果你想看到详细配置更新过程,可以使用以下类似命令查看。

1
2
3
$ kubectl logs -f [metallb-controller-pod]
或者 
$ kubectl logs -l component=speaker -n metallb-system

接下来,我们来创建一个服务类型为 LoadBalancer 的 Nginx 服务来验证下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ cat nginx-test.yaml

apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1
ports:
- name: http
containerPort: 80

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

服务创建完成,运行 kubectl apply -f nginx-test.yaml 命令后,我们可以看到对应服务信息。

1
2
3
4
5
6
7
$ 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

从输出结果,我们可以看到 LoadBalancer 类型的服务,并且分配的外部 IP 地址是地址池中的第一个 IP 192.168.0.10

最后,我们通过 curl http://192.168.0.10 命令来验证下,发现可以正常显示 Nginx 的欢迎信息。

1
2
3
4
5
6
7
8
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
................
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

至此,MetalLB Layer 2 模式的配置就结束了。

配置 MetalLB 为 BGP 模式

对于配置为具有一个 BGP 路由器和一个 IP 地址范围的 BGP 模式,你需要先准备好以下 4 条配置信息:

  1. MetalLB 应连接的路由器 IP 地址。

  2. 路由器的 AS 号。

  3. MetalLB 应该使用的 AS 编号。

  4. IP 地址范围,表示为 CIDR 前缀。

由于这种配置方式需要具备 BGP 功能的硬件路由器支持,目前我们环境中不具备此等条件。这里就简单说下 MetalLB 对应的配置方式,具体内容就不展开讲解了。

由于前面已经安装了 MetalLB 的 ControllerSpeaker,只是使用的是 Layer 2 模式。这里只需要改为 BGP 模式,我们修改 Configmap 中 Config 配置就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 假如要为 MetalLB 提供范围 192.168.9.0/24 和 AS 号 65009,并将其连接到 192.168.0.1 的 AS 号为 65000 的路由器。
$ cat MetalLB-BGP-Config.yaml

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

总结

本文简单介绍了 MetalLB 的用途以及 MetalLB 的两种部署模式:Layer 2 模式和 BGP 模式。在实际应用中,如果条件满足,推荐使用 BGP 模式。

参考资料

  1. http://www.google.com

  2. https://blog.fleeto.us/post/intro-metallb/

  3. https://ieevee.com/tech/2019/06/30/metallb.html

  4. https://blog.csdn.net/kunyus/article/details/88616653

  5. https://vqiu.cn/metallb-si-you-ji-qun-loadbalancer/amp/

  6. https://sre.ink/metallb-kubernetes-loadbalancer-no-ipvs/

  7. https://blog.csdn.net/networken/article/details/85928369

  8. https://blog.gmem.cc/external-lb-for-on-premise-k8s-cluster

  9. https://leeif.me/2019/02/k8s-deploy-metallb-LoadBalancer.html

  10. https://mshk.top/2019/04/kubernetes-metallb-loadbalancer-nginx-ingress-controller/