MetalLB 是使用标准路由协议(ARP/BGP)为 bare metal Kubernetes 集群实现的负载平衡器。
L2 模式 (ARP)
L2 模式下,MetalLB 会通过 memberlist 选举出一个 Leader 节点,此节点负责向本地网络宣告 LoadBalancerIP。 从网络的角度来看,这台机器似乎有多个 IP 地址,它会响应来自 LoadBancerIP 的 ARP 请求。 L2 模式最大的优势是它不需要依赖譬如路由器等硬件的依赖便可工作。
- 优势:通用型,不需要额外的硬件支持
- 缺点:单节点的带宽限制、稍缓慢的故障转移(10s 左右)
L3 模式 (BGP)
在 BGP 模式下,集群中的每个节点都会与路由器建立 BGP Peer,并使用该会话向集群外部通告集群服务的 LoadBalanceIP。 BGP Router 基于每个不同的连接选择一个下一跳(即集群某个节点,这不同于 L2 模式下所有流量先到达某个 Leader 节点)。
参考文档:https://metallb.io/installation/
1 2 3
| helm repo add metallb https://metallb.github.io/metallb helm repo update helm -n metallb-system upgrade --install metallb metallb/metallb --create-namespace
|
1 2 3 4 5 6
| root@test-0:~# kubectl get pod -n metallb-system NAME READY STATUS RESTARTS AGE metallb-controller-9bf78f497-twzcz 1/1 Running 0 4m56s metallb-speaker-db2vv 4/4 Running 0 4m56s metallb-speaker-kt45g 4/4 Running 0 4m56s metallb-speaker-pjxm9 4/4 Running 0 4m56s
|
IP Address Pool
顾名思义,池子中的 IP 就是分配给 Service 使用的 VIP。
默认情况下,MetalLB 会自动分配池子中的 IP,这可能会造成浪费,可以在通过 autoAssign: false
避免这个问题,同时为了避免 .0 和 .255 这样的 IP 被分配,可以将 avoidBuggyIPs
设置为 true
。
1 2 3 4 5 6 7 8 9 10 11 12
| cat <<EOF | kubectl apply -f - apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 172.16.16.0/24 autoAssign: false avoidBuggyIPs: true EOF
|
IP 池也支持指定特定的 Namespace 和 Service 使用:
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
| cat <<EOF | kubectl apply -f - apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 172.16.16.0/24 autoAssign: false avoidBuggyIPs: true serviceAllocation: # 权重为 50,value 越小代表权重越高,1 代表最高,0 /没设置 priority 代表最低,优先级相同则随机选择 priority: 50 # IP 可以分配到下面的 Namespace 中,或者包含下面 label 的 Namespace 中 namespaces: - default namespaceSelectors: - matchLabels: foo: bar # 在上述匹配的 Namespace 中,匹配标签为 app=nginx 的 Service 才能够分配 IP serviceSelectors: - matchExpressions: - {key: app, operator: In, values: [nginx]} EOF
|
L2 Configuration
默认情况下,只有一个节点会被选出来宣告 VIP,这个节点被称为 Leader 节点。
正常情况下所有节点的 Speaker 都可以宣告 VIP,但在某些特殊情况下,VIP 只有在部分节点上能够使用,这时候可以通过使用 L2Advertisement CR 中的 nodeSelector 来实现。

在下面的例子中,first-pool
中的 VIP 只会被 test-1
节点宣告:
1 2 3 4 5 6 7 8 9 10 11 12 13
| cat <<EOF | kubectl apply -f - apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: example namespace: metallb-system spec: ipAddressPools: - first-pool nodeSelectors: - matchLabels: kubernetes.io/hostname: test-1 EOF
|
也可以指定网卡:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| cat <<EOF | kubectl apply -f - apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: example namespace: metallb-system spec: ipAddressPools: - first-pool nodeSelectors: - matchLabels: kubernetes.io/hostname: test-1 interfaces: - eth0 EOF
|
Service 使用 VIP
在 Service 指定 IP Address Pool,会从 Pool 中随机获取 IP 使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| kubectl create deployment nginx --image harbor.warnerchen.com/library/nginx:mainline
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: annotations: metallb.io/ip-allocated-from-pool: first-pool metallb.universe.tf/address-pool: first-pool labels: app: nginx name: nginx namespace: default spec: ports: - name: port-80 port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer EOF
|
即可使用 VIP 访问服务:

同时也可以看到在对应节点进行的宣告:

如果要指定 IP,可以通过下面的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: annotations: metallb.io/ip-allocated-from-pool: first-pool metallb.universe.tf/address-pool: first-pool metallb.universe.tf/loadBalancerIPs: 172.16.16.201 labels: app: nginx name: nginx namespace: default spec: ports: - name: port-80 port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer EOF
|
IP 也可以被多个 Service 共享使用,通过端口进行区分:
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 37 38 39 40 41 42 43 44
| cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: annotations: metallb.io/ip-allocated-from-pool: first-pool metallb.universe.tf/address-pool: first-pool metallb.universe.tf/allow-shared-ip: "nginx" labels: app: nginx name: nginx-1 namespace: default spec: ports: - name: port-80 port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer
--- apiVersion: v1 kind: Service metadata: annotations: metallb.io/ip-allocated-from-pool: first-pool metallb.universe.tf/address-pool: first-pool metallb.universe.tf/allow-shared-ip: "nginx" labels: app: nginx name: nginx-2 namespace: default spec: ports: - name: port-81 port: 81 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer EOF
|
