Akemi

使用MetalLB创建私有云LB service

2025/09/16

MetalLB是一个开源的负载均衡器,为私有云环境中的k8s集群设计。使用标准网络协议来实现外部流量的负载均衡,使k8s可以跟像公有云环境一样使用loadbalancer类型的service。MetalLB也是CNCF的沙盒项目

Installation :: MetalLB, bare metal load-balancer for Kubernetes

这种方法的下位替代就是做haproxy+NodePort,也可以起到负载均衡的作用

工作模式

  • 分配一个地址池,从地址池中拿IP分配给LB service
  • 分配地址后使用Layer2/BGP模式

L2模式直接使用ARP和NDP进行通告
BGP模式需要与网络设备建立会话,通告负载均衡地址

使用metallb,其实是在地址池里分了个ip当做某个服务的VIP,不需要像nodeport一样关心访问的节点和端口是哪个,直接访问这个VIP就完事了,而且可以提供标准的端口,更加清爽与安全

MetalLB组件

  • Controller:deployment,负责监听k8s service的变更,分配和回收地址
  • Speaker:daemonset,负责对外广播service的IP地址

MetalLB部署—资源文件部署

除了资源文件部署还可以通过helm部署,但是略过了,因为这个东西不需要手动配置什么,那helm肯定更加简单

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
45
46
47
48
49
50
51
52
如果使用的是calico,且使用的是ipvs模式
需要修改kube-proxy配置
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system

kubectl -n kube-system rollout restart daemonset kube-proxy

直接使用配置安装
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

我的MetalLB版本是v0.15.2
需求镜像:
quay.io/metallb/controller:v0.15.2
quay.io/metallb/speaker:v0.15.2

kubectl get pods -n metallb-system
NAME READY STATUS RESTARTS AGE
controller-679d565488-xmhgj 1/1 Running 0 21m
speaker-52q4b 1/1 Running 0 21m
speaker-8pqqc 1/1 Running 0 21m
speaker-d2t9s 1/1 Running 0 21m
speaker-hq86m 1/1 Running 0 21m
speaker-tvfl4 1/1 Running 0 21m
speaker-w9tbh 1/1 Running 0 21m

创建地址池资源
cat > metaippool.yaml <<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ip-pool
namespace: metallb-system
spec:
addresses:
- 10.163.2.200-10.163.2.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- ip-pool
EOF
kubectl apply -f metaippool.yaml

kubectl get IPAddressPool -A
NAMESPACE NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
metallb-system ip-pool true false ["10.163.2.200-10.163.2.220"]

创建测试service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat > empty-svc.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: empty-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
EOF

kubectl apply -f empty-svc.yaml
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
csi-metrics-rbdplugin ClusterIP 10.233.6.103 <none> 8080/TCP 22h
csi-rbdplugin-provisioner ClusterIP 10.233.38.11 <none> 8080/TCP 22h
empty-service LoadBalancer 10.233.32.246 10.163.2.200 80:31546/TCP 1s
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 4d14h

可以看到这个空service已经获得了一个VIP

后记

如果只用metallb还会存在一个问题,每个service都需要占用一个VIP,那服务一多不就炸了吗,所以可以与ingress结合,这样使用就可以只使用同一个IP/域名

再结合ingress路由或者双层代理的方式将流量路由到后端pod

CATALOG
  1. 1. MetalLB部署—资源文件部署
    1. 1.1. 创建测试service
    2. 1.2. 后记