MetalLB 是用于裸金属 Kubernetes 集群的负载均衡器实现,它使用标准路由协议。
注意:
MetalLB 是一个年轻项目。目前处于 Beta 阶段。project maturity 页面讲述了这意味着什么。
对于裸金属集群,Kubernetes 未提供网络负载均衡器(LoadBalancer 类型的 Service)实现。Kubernetes 附带的网络负载均衡器实现都是调用各种 IaaS 平台(GCP、AWS、Azure...)的胶水代码。如果不是运行在受支持的 IaaS 平台上,负载均衡器在创建时,将无限期地保持在“pending”状态。
逻金属集群的操作者只能用两个较小的工具,来将用户流量引进集群,“NodePort”和“externalIPs” Service。这两种选择在生产使用中都有显著的缺点,这使得裸金属集群在 Kubernetes 生态系统中属于二等公民。
MetalLB 旨在通过提供与标准网络设备集成的网络负载均衡器实现来纠正这种不平衡,从而使裸金属集群上的外部服务也尽可能地“正常工作”。
MetalLB 与 Kubernetes 集群挂钩,提供网络负载平衡器实现。简而言之,它允许你在非云提供商的集群中,创建 LoadBalancer 类型的 Kubernetes 服务,而非简单地与付费产品挂钩,来提供负载均衡器。
MetalLB 有两个功能共同提供这项服务:地址分配和外部公告。
在云提供商的 Kubernetes 集群中,你请求负载均衡器,云平台为你分配 IP 地址。在裸金属集群,MetalLB 负责该分配。
MetalLB 不能凭空创建 IP 地址,因此必须指定它可以使用的 IP 地址池。随着服务的来来去去,MetalLB 将负责分配和取消分配单独的地址,但它只分发属于其配置池的 IP。
如何获取 MetalLB 的 IP 地址池取决于你的环境。如果你在托管设施中运行裸金属集群,你的主机提供商可能提供用于租赁的 IP 地址。在该情况下,你可以租赁,比如 a/26 的 IP 空间(64 个地址),并将该范围提供给 MetalLB 用于集群服务。
或者,你的集群可能是纯私有的,向附近的局域网提供服务,但不暴露在互联网上。在这种情况下,你可以从一个私有地址空间(所谓的 RFC1918 地址)中选择一系列 IP。然后将它们分配给 MetalLB。这样的地址是免费的,如果你只向局域网提供服务,那么它可以正常工作。
或者,你可以两者都做!MetalLB 允许你定义任意数量的地址池,并且不关心你给它提供什么“类型”的地址。
MetalLB 为 Service 分配外部 IP 地址后,它需要让集群之外的网络意识到 IP “存在”于集群中。MetalLB 使用标准的网络或路由协议来实现这一点,具体取决于使用哪种模式:ARP、NDP 或 BGP。
在 L2 模式中,集群中的一台机器拥有服务的所有权,该机器使用标准的地址发现协议(用于 IPv4 的 ARP,用于 IPv6 的 NDP),使这些 IP 地址在本地网络中可达。从局域网的角度来看,公告机器只是拥有多个 IP 地址。
在 BGP 模式下,集群中的所有机器都与你控制的附近路由器建立 BGP 对等会话,告诉这些路由器如何将流量转发到 Service IP。使用 BGP 可以实现跨多个节点的真正负载均衡,以及基于 BGP 策略机制的细粒度流量控制。
安装 MetalLB 的方式有三种:使用普通 Kubernetes 清单、使用 Kustomize 或使用 Helm。
如果你在 IPVS 模式下使用 kube-proxy,从 Kubernetes v1.14.2 开始,必须启用严格 ARP 模式。
注意,如果使用 kube-router 作为 service-proxy,则不需要这样做,因为它默认启用严格 ARP。
可以通过编辑当前集群的 kube-proxy 配置来实现:
kubectl edit configmap -n kube-system kube-proxy
然后设置:
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
strictARP: true
也可以将该配置片段添加到 kubeadm-config,只需在主配置后面使用 ---
追加它即可。
如果你试图自动化此更改,这些 shell 片段可能会帮助你:
# see what changes would be made, returns nonzero returncode if different
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl diff -f - -n kube-system
# actually apply the changes, returns nonzero returncode on errors only
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
可以使用 Helm 安装 MetalLB,Helm Chart 仓库在 https://metallb.github.io/metallb
。
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb
在安装时,可以指定 values 文件:
helm install metallb metallb/metallb -f values.yaml
注意:
Speaker Pod 需要更高的权限,才能执行其网络功能。
如果你在强制执行 pod security admission(在 k8s 1.23 中处于 beta 阶段)的 kubernetes 版本中使用 MetalLB,那么部署 MetalLB 的命名空间必须被标记为:
labels
pod-security.kubernetes.io/enforce privileged
pod-security.kubernetes.io/audit privileged
pod-security.kubernetes.io/warn privileged
注意:
如果想使用 FRR mode 部署 MetalLB,必须设置如下值:
speaker:
frr:
enabled: true
在配置之前,MetalLB 处于空闲状态。通过创建和部署各种资源到 MetalLB 被部署到的相同命名空间(metallb-system)的方式,完成配置工作。
在 configsamples
中,有许多配置 CR 的示例。
另外,这里有完整的 API 文档。
注意:
如果使用 Helm 安装 MetalLB,需要更改 CR 的命名空间,以匹配部署 MetalLB 的命名空间。
为给 Service 分配 IP,必须通过 IPAddressPool
CR 指示 MetalLB 这样做。
通过 IPAddressPool
分配的所有 IP 构成 MetalLB 用于向 Service 分配 IP 的 IP 池。
apiVersion metallb.io/v1beta1
kind IPAddressPool
metadata
name first-pool
namespace metallb-system
spec
addresses
192.168.10.0/24
192.168.9.1-192.168.9.5
fc00:f853:0ccd:e799::/124
多个IPAddressPool
实例可以共同存在,可以通过 CIDR 或范围定义地址,IPV4 和 IPV6 地址均可分配。
一旦 IP 地址被分配给 Service,那么必须公告它们。
具体配置取决于用于公告 Service IP 的协议。跳转到:
注意:可以同时通过 L2 和 BGP 公告相同的 Service(查看相关的 FAQ)。
L2 模式的配置最简单:在许多情况下,无需任何协议特定的配置,只需 IP 地址。
L2 模式不需要将 IP 地址绑定到工作节点的网络接口上,它的工作原理是直接响应本地网络上的 ARP 请求,将机器的 MAC 地址提供给客户端。
为发布来自 IPAddressPool
的 IP,L2Advertisement
实例必须与 IPAddressPool
相关联。
例如,以下配置使 MetalLB 控制从 192.168.1.240 到 192.168.1.250 之间的 IP,并配置 L2 模式:
apiVersion metallb.io/v1beta1
kind IPAddressPool
metadata
name first-pool
namespace metallb-system
spec
addresses
192.168.1.240-192.168.1.250
apiVersion metallb.io/v1beta1
kind L2Advertisement
metadata
name example
namespace metallb-system
在 L2Advertisement
实例中未设置 IPAddressPool
选择器将被解释为该实例关联到所有可用的 IPAddressPool
。
因此,如果有专门的 IPAddressPool
,并且只有部分 IPAddressPool
必须通过 L2 发布,那么必须声明我们想发布的 IP 所在的 IPAddressPool
的列表(另一种选择是使用标签选择器):
apiVersion metallb.io/v1beta1
kind L2Advertisement
metadata
name example
namespace metallb-system
spec
ipAddressPools
first-pool
创建 IPAddressPool 和 L2Advertisement 实例:
注意:
- 按需修改名称、Namespace 和 IP 池。
apiVersion metallb.io/v1beta1
kind IPAddressPool
metadata
name test-pool
namespace default
spec
addresses
192.168.56.110-192.168.56.119
---
apiVersion metallb.io/v1beta1
kind L2Advertisement
metadata
name test-l2
namespace default
spec
ipAddressPools
test-pool
创建测试 Deployment:
kubectl create deploy nginx --image nginx:latest --port 80 -n default
创建 Service,类型选择 LoadBalancer:
kubectl expose deployment nginx --name nginx-lb --port 80 --target-port 80 --type LoadBalancer -n default
查看 Service:
$ kubectl get svc nginx-lb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-lb LoadBalancer 10.110.112.15 192.168.56.110 80:32541/TCP 14s
在集群外访问:
$ arp 192.168.56.110
localhost (192.168.56.110) at 8:0:27:ab:94:55 on vboxnet0 ifscope [ethernet]
$ curl http://192.168.56.110
<!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>
L2 模式有两个主要限制:单节点瓶颈和潜在的缓慢故障转移。
在 L2 模式下,单个领导节点为 Service IP 接收所有流量,这意味着服务的入口带宽被限制为单个节点的带宽。这是使用 ARP 和 NDP 引导流量的基本限制。
在当前实现中,节点之间的故障转移依赖客户端的合作。当发生故障转移时,MetalLB 发送大量“无缘无故的” L2 数据包(实际上应该称为“未经请求的 L2 数据包”),以通知客户端与 Service IP 相关联的 MAC 地址已更改。
大多数操作系统正确地处理“无缘无故的” L2 数据包,及时更新它们的邻居缓存。在这种情况下,故障转移将在几秒内发生。然而,一些系统要么根本没实现“无缘无故的”处理,要么拥有错误的实现,导致缓存更新延迟。
主要操作系统(Windows、Mac、Linux)的所有现代版本都正确地实现了 L2 故障转移,因此唯一可能发生问题的情况是使用较老或不常见的操作系统。
为尽量减少有计划的故障转移对有 Bug 的客户端的影响,应该在切换领导权后,让旧的领导节点保持运行几分钟,以便它可以继续为旧客户端转发流量,直到它们的缓存刷新。
在计划外的故障转移期间,Service IP 将不可达,直到有 Bug 的客户端刷新其缓存项。