惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
Jina AI
Jina AI
C
Check Point Blog
V
V2EX
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
A
About on SuperTechFans
D
DataBreaches.Net
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
博客园_首页
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

i4T

OpenClaw在Macmini下网络HTTPS_Proxy代理配置 | i4T 容器化部署OpenClaw授权View权限对Kubernetes集群进行巡检故障排查 | i4T 初试VictoriaLogs集群采集Kubernetes Pod日志 | i4T Kubernetes 部署Elasticsearch为WordPress提供文章搜索 | i4T Kubernetes使用Prometheus监控爱快路由器iKuai_Exporter | i4T RustDesk API集成Authentik ODIC单点登录 | i4T Kubernetes 部署RustDesk API实现专业版功能及管理Web UI | i4T 使用Kubernetes 快速部署RustDesk替换向日葵toDesk进行远程连接 | i4T Authentik 集成群晖Synology DSM 实现单点登录 | i4T Authentik 集成Kubernetes Grafana 实现SSO单点登录 | i4T Authentik 集成接入VMware vCenter 8.0.3实现ldP身份提供商登录 | i4T Kubernetes v1.29.9部署Authentik 统一认证平台并接入Harbor | i4T 二进制Kafka_2.13-3.9.0集群开启并配置ACL用户授权 | i4T R730 ESXI 8.0平台PCI直通2080Ti 实现Windows远程游戏以及AI模型 | i4T Dell R730虚拟化ESXI8.0.3平台使用丽台Tesla V100配置vGPU | i4T Kubernetes使用HostAliases手动为容器Pod添加hosts解析 | i4T Nginx 使用resolver变量实现动态DNS解析配置 | i4T Kubernetes 1.29.0 部署配置Ingress-nginx-controller | i4T Ubuntu环境下Docker Compose配置Harbor开机自启 | i4T Dell PowerEdge R730更新iDRAC8版本 | i4T Kubernetes部署RedisShake实现Redis哨兵异地灾备 | i4T Kubernetes部署开源Excalidraw实现在线绘图 | i4T Kubernetes部署DNSmgr聚合公网DNS多平台域名解析系统及SSL自续签 | i4T Kubernetes Grafana数据从Sqlite3迁移到MySQL | i4T 宝塔内网Nginx获取公网宝塔Nginx用户真实IP | i4T 基于Kubernetes Categraf SNMP插件采集Dell R730服务器硬件并使用Grafana监控 | i4T Kubernetes v1.29.9安装Grafana 12并开启匿名访问 | i4T Containerd 配置免费镜像加速源 | i4T Docker集成Containerd实现容器管理 | i4T
Kubernetes LoadBalancer负载均衡外部访问方案MetalLB | i4T
https://i4t.com/users/auuAwtzuk · 2025-08-05 · via i4T

Kubernetes不为裸机集群提供网络负载均衡器(LoadBalancer服务)的实现。 裸机集群只能使用NodePort和externalIPs服务来将用户流量引入他们的集群,Metallb旨在通过提供负载均衡器以便裸机集群上的外部服务可以更好工作。

MetalLB是k8s生态中的AddOn之一,分为controller和speaker两个组件。

  • Controller通过k8s api-server监听service变化,给与service一个服务IP或回收该IP。
  • Speaker组件采用Layer2或BGP模式走api-server将流量引入集群,k8s再通过kube-proxy,走iptables或ipvs,将流量引入pod。此外speaker还会负责服务IP驻守节点的选举,当该节点宕机时,会举行重新选举,从而实现HA。

服务IP需要k8s维护者自己给定同k8s集群同网段的一个多个IP地址,作为服务IP池,以便创建service时,可以使用其中的某个IP作为会漂移的服务IP。

工作原理

具体的工作原理如下图所示,Controller负责监听Service变化,当Service配置为LoadBalancer模式时,从IP池分配给到相应的IP地址并对该IP的生命周期进行管理。Speaker则会依据选择的协议进行相应的广播或应答,实现IP地址的通信响应。当业务流量通过TCP/UDP协议到达指定的Node时,由Node上面运行的Kube-Proxy组件对流量进行处理,并分发到对应服务的Pod上面。

Kubernetes LoadBalancer负载均衡外部访问方案MetalLB

MetalLB支持两种模式,一种是Layer2模式,一种是BGP模式。

本次演示环境,我们采用Layer2模式

  • Layer2模式

在2层模式下,Metallb会在Node节点中选出一台作为Leader,与服务IP相关的所有流量都会流向该节点。在该节点上, kube-proxy将接收到的流量传播到对应服务的Pod。当leader节点出现故障时,会由另一个节点接管。从这个角度来看,2层模式更像是高可用,而不是负载均衡,因为同时只能在一个节点负责接收数据。

在二层模式中会存在以下两种局限性:单节点瓶颈和故障转移慢的情况

由于Layer 2 模式会使用单个选举出来的Leader来接收服务IP的所有流量,这就意味着服务的入口带宽被限制为单个节点的带宽,单节点的流量处理能力将成为整个集群的接收外部流量的瓶颈。

在故障转移方面,目前的机制是MetalLB通过发送2层数据包来通知各个节点,并重新选举Leader,这通常能在几秒内完成。但如果是计划外的事故导致的,此时在有故障的客户端刷新其缓存条目之前,将无法访问服务IP。

BGP模式

BGP模式是真正的负载均衡,该模式需要路由器支持BGP协议 ,群集中的每个节点会与网络路由器建议基于BGP的对等会话,并使用该会话来通告负载均衡的IP。MetalLB发布的路由彼此等效,这意味着路由器将使用所有的目标节点,并在它们之间进行负载平衡。数据包到达节点后,kube-proxy负责流量路由的最后一跳,将数据包发送到对应服务的Pod。

负载平衡的方式取决于您特定的路由器型号和配置,常见的有基于数据包哈希对每个连接进行均衡,这意味着单个TCP或UDP会话的所有数据包都将定向到群集中的单个计算机。

BGP模式也存在着自身的局限性,该模式通过对数据包头中的某些字段进行哈希处理,并将该哈希值用作后端数组的索引,将给定的数据包分配给特定的下一跳。但路由器中使用的哈希通常不稳定,因此只要后端节点数量发生变化时,现有连接就会被随机地重新哈希,这意味着大多数现有连接将被转发到另一后端,而该后端并不清楚原有的连接状态。为了减少这种麻烦,建议使用更加稳定的BGP算法,如:ECMP散列算法。

安装配置MetalLB

如果我们只使用Ingress-NGINX,不创建LoadBalancer,访问则需要Ingress svc port访问

不安装LoadBalancer 则ADDRESS将没有分配IP

root@k8s-master-01:~/metallb# kubectl get ingress
NAME                 CLASS   HOSTS           ADDRESS   PORTS   AGE
ingress-nginx-demo   nginx   nginx.frps.cn             80      86m

kube-proxy节点配置

kubectl edit configmap -n kube-system kube-proxy

    kind: KubeProxyConfiguration
    logging:
      flushFrequency: 0
      options:
        json:
          infoBufferSize: "0"
      verbosity: 0
    metricsBindAddress: 0.0.0.0:10249
    mode: ipvs
    ### 以下为新增配置
    ipvs:
      strictARP: true

下载部署文件

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.2/config/manifests/metallb-native.yaml

#符合国内网络下载
kubectl apply -f https://d.frps.cn/file/kubernetes/metallb/metallb-native.yaml

如果有镜像镜像无法下载可以使用我本地的镜像导入

wget https://d.frps.cn/file/kubernetes/metallb/metallb_0.15.2.tar
#docker load -i 导入即可

执行结果如下

root@k8s-master-01:~/metallb# kubectl apply -f metallb-native.yaml
namespace/metallb-system created
customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created
customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created
customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created
customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created
customresourcedefinition.apiextensions.k8s.io/servicebgpstatuses.metallb.io created
customresourcedefinition.apiextensions.k8s.io/servicel2statuses.metallb.io created
serviceaccount/controller created
serviceaccount/speaker created
role.rbac.authorization.k8s.io/controller created
role.rbac.authorization.k8s.io/pod-lister created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/controller created
rolebinding.rbac.authorization.k8s.io/pod-lister created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
configmap/metallb-excludel2 created
secret/metallb-webhook-cert created
service/metallb-webhook-service created
deployment.apps/controller created
daemonset.apps/speaker created
validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created

这里会为我们额外创建一个metallb-system命名空间

root@k8s-master-01:/tmp# kubectl get ns
NAME                           STATUS   AGE
default                        Active   33d
extension-openpitrix           Active   29d
extension-whizard-telemetry    Active   29d
ingress-nginx                  Active   12h
kube-node-lease                Active   33d
kube-public                    Active   33d
kube-system                    Active   33d
kubesphere-controls-system     Active   29d
kubesphere-monitoring-system   Active   29d
kubesphere-system              Active   29d
metallb-system                 Active   35s
middle                         Active   31d
tools                          Active   31d
wordpress                      Active   31d

检查metallb状态

root@k8s-master-01:~/metallb# kubectl get all -n metallb-system
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-8666ddd68b-47qm5   1/1     Running   0          3m9s
pod/speaker-5cg4j                 1/1     Running   0          3m9s
pod/speaker-cxvsm                 1/1     Running   0          3m9s
pod/speaker-h9px8                 1/1     Running   0          3m9s
pod/speaker-k2q2m                 1/1     Running   0          3m9s
pod/speaker-lr2v2                 1/1     Running   0          3m9s
pod/speaker-tbvmc                 1/1     Running   0          3m9s

NAME                              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/metallb-webhook-service   ClusterIP   10.96.0.81   <none>        443/TCP   3m9s

NAME                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/speaker   6         6         6       6            6           kubernetes.io/os=linux   3m9s

NAME                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/controller   1/1     1            1           3m9s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/controller-8666ddd68b   1         1         1       3m9s

要使用·Layer2模式进行配置,需要创建一个IPAddressPool资源对象,用来指定用于分配的IP池

root@k8s-master-01:~/metallb# cat ip-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: ip-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.21.60-192.168.21.70

然后需要创建一个广播声明,可以关联上面的 IP 池对象,这样会使用关联的 IP 池地址。为了通告来自IPAddressPool的IP,L2Advertisement实例必须关联到 IPAddressPool。

比如上面的配置可以让 MetalLB控制从192.168.21.60-192.168.21.70 IP地址。

root@k8s-master-01:~/metallb# cat advertise.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2adver
  namespace: metallb-system
spec:
  ipAddressPools: # 如果不配置则会通告所有的IP池地址
    - ip-pool

创建测试NGINX Pod及SVC

root@k8s-master-01:~/metallb# cat test-nginx.yaml
# test-lb.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          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

查看Ingress IP

root@k8s-master-01:~/metallb# kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1     <none>          443/TCP        25d
nginx        LoadBalancer   10.96.1.139   192.168.21.60   80:32473/TCP   18m
root@k8s-master-01:~/metallb#
root@k8s-master-01:~/metallb#
root@k8s-master-01:~/metallb# curl 192.168.21.60
<!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>

在每台 K8s 节点机器上面的 kube-ipvs0 网卡上面都能看到这个 LoadBalancer 的 VIP:

root@k8s-master-01:~# ip a|grep 192
    inet 192.168.21.10/24 brd 192.168.21.255 scope global ens34
    inet 192.168.21.60/32 scope global kube-ipvs0

结合Ingress-nginx-controller配置使用

测试文件如下

在测试文件中,我们使用了ingressClassName: nginx 这里的配置就是使用我们前面部署的Ingress-nginx控制器,结合ingress-nginx控制器进行访问

# lb-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: lb-demo
  namespace: default
spec:
  selector:
    matchLabels:
      app: lb-demo
  template: # pod 模板
    metadata:
      labels:
        app: lb-demo
    spec:
      containers:
        - name: app
          image: nginx
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: lb-demo
  namespace: default
spec:
  selector:
    app: lb-demo
  ports:
    - name: http
      port: 80 # 这个是Service的端口
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: lb-demo
  namespace: default
spec:
  ingressClassName: nginx
  rules:
    - host: nginx1.frps.cn
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: lb-demo
                port:
                  number: 80

接下来查看svc以及Ingress就已经生效了

root@k8s-master-01:/tmp# kubectl get ingress,svc
NAME                                           CLASS   HOSTS            ADDRESS         PORTS   AGE
ingress.networking.k8s.io/lb-demo              nginx   nginx1.frps.cn   192.168.21.60   80      34s

NAME                         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/kubernetes           ClusterIP   10.96.0.1     <none>        443/TCP   33d
service/lb-demo              ClusterIP   10.96.3.241   <none>        80/TCP    34s

结合我们上一篇文章,配置Ingress-nginx-controller 上面创建的Ingress会自动关联到 LoadBalancer MetalLB

root@k8s-master-01:/tmp# kubectl get ingress
NAME                 CLASS   HOSTS           ADDRESS   PORTS   AGE
ingress-nginx-demo   nginx   nginx.frps.cn             80      152m

#等待几分钟后,节点自动绑到LoadBalancer上

root@k8s-master-01:/tmp# kubectl get ingress
NAME                 CLASS   HOSTS           ADDRESS         PORTS   AGE
ingress-nginx-demo   nginx   nginx.frps.cn   192.168.21.60   80      152m

绑定浏览器访问

绑定到我们声明的192.168.21.60IP

192.168.21.60  #IP在我们每一台节点都运行

Kubernetes LoadBalancer负载均衡外部访问方案MetalLB