Image

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

释放双眼,带上耳机,听听看~!

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

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控制器进行访问

Image
Image

Kubernetes 1.29.0 部署配置Ingress-nginx-controller

 

# 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

给TA打赏
共{{data.count}}人
人已打赏
KubernetesNGINX

Kubernetes 1.29.0 部署配置Ingress-nginx-controller

2025-8-5 18:12:30

NGINX

Nginx 使用resolver变量实现动态DNS解析配置

2025-8-6 23:36:29

0 条回复 A文章作者 M管理员
Image
Image
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索
NEW
特斯拉V100 智能助理×
本机器助手只回答博客已有内容!