Deploying MetalLB Load Balancer on Bare‑Metal Kubernetes Clusters
This article explains why exposing services on a bare‑metal Kubernetes cluster requires a custom load‑balancer solution, introduces MetalLB, details its deployment requirements, explains its Layer 2 and BGP modes, provides step‑by‑step installation commands, and shows how to verify the setup.
When a service is deployed on Kubernetes, exposing it to external users is trivial on cloud platforms (such as Alibaba Cloud, Tencent Cloud, AWS) using the cloud provider’s LoadBalancer service. However, on a self‑built bare‑metal Kubernetes cluster, the default networking does not support load balancing, so alternatives like Ingress, NodePort, or ExternalIPs must be used, each with its own drawbacks.
MetalLB addresses this pain point by providing a LoadBalancer implementation that integrates with standard network devices, allowing external services to run normally on bare‑metal clusters and reducing operational overhead.
Deployment Requirements
Kubernetes version 1.13.0 or higher without built‑in network load balancing.
A pool of IPv4 addresses for MetalLB allocation.
If using BGP mode, one or more routers that support BGP.
For Layer 2 mode, nodes must allow traffic on port 7946 for speaker communication.
The cluster network must be compatible with MetalLB (see compatibility table below).
Network Type
Compatibility
Antrea
Yes
Calico
Mostly
Canal
Yes
Cilium
Yes
Flannel
Yes
Kube‑ovn
Yes
Kube‑router
Mostly
Weave Net
Mostly
How MetalLB Works
MetalLB consists of two components: a Controller (deployed as a Deployment) and a Speaker (deployed as a DaemonSet on every node). The Controller watches Service objects; when a Service is set to LoadBalancer type, the Controller allocates an IP from the configured pool and manages its lifecycle. The Speaker advertises the allocated IP using either Layer 2 ARP announcements or BGP announcements, depending on the chosen mode. Traffic arriving at a node is first handled by kube‑proxy, which forwards it to the appropriate Pod.
Installation Steps
Enable ARP mode for kube‑proxy if the cluster uses IPVS (required from Kubernetes v1.14.2 onward):
$ kubectl edit configmap -n kube-system kube-proxy</code>
<code># set strictARP to true</code>
<code>apiVersion: kubeproxy.config.k8s.io/v1alpha1</code>
<code>kind: KubeProxyConfiguration</code>
<code>mode: "ipvs"</code>
<code>ipvs:</code>
<code> strictARP: trueInstall MetalLB components (default namespace metallb-system):
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yamlConfigure the desired mode.
Layer 2 mode : create an IPAddressPool and a L2Advertisement.
apiVersion: metallb.io/v1beta1</code>
<code>kind: IPAddressPool</code>
<code>metadata:</code>
<code> name: ip-pool</code>
<code> namespace: metallb-system</code>
<code>spec:</code>
<code> addresses:</code>
<code> - 192.168.214.50-192.168.214.80 # IP pool for the LB apiVersion: metallb.io/v1beta1</code>
<code>kind: L2Advertisement</code>
<code>metadata:</code>
<code> name: l2adver</code>
<code> namespace: metallb-systemBGP mode : define a BGPPeer, an IPAddressPool, and a BGPAdvertisement.
apiVersion: metallb.io/v1beta2</code>
<code>kind: BGPPeer</code>
<code>metadata:</code>
<code> name: sample</code>
<code> namespace: metallb-system</code>
<code>spec:</code>
<code> myASN: 64500</code>
<code> peerASN: 64501</code>
<code> peerAddress: 10.0.0.1 apiVersion: metallb.io/v1beta1</code>
<code>kind: IPAddressPool</code>
<code>metadata:</code>
<code> name: first-pool</code>
<code> namespace: metallb-system</code>
<code>spec:</code>
<code> addresses:</code>
<code> - 192.168.10.0/24 apiVersion: metallb.io/v1beta1</code>
<code>kind: BGPAdvertisement</code>
<code>metadata:</code>
<code> name: bgpadver</code>
<code> namespace: metallb-systemValidate the installation by creating a sample Service and Deployment using LoadBalancer type, checking that an external IP is assigned, and accessing the application from a browser.
apiVersion: v1</code>
<code>kind: Service</code>
<code>metadata:</code>
<code> name: myapp-svc</code>
<code>spec:</code>
<code> selector:</code>
<code> app: myapp</code>
<code> ports:</code>
<code> - protocol: TCP</code>
<code> port: 80</code>
<code> targetPort: 80</code>
<code> type: LoadBalancer</code>
<code>---</code>
<code>apiVersion: apps/v1</code>
<code>kind: Deployment</code>
<code>metadata:</code>
<code> name: myapp-deployment</code>
<code>spec:</code>
<code> replicas: 2</code>
<code> selector:</code>
<code> matchLabels:</code>
<code> app: myapp</code>
<code> template:</code>
<code> metadata:</code>
<code> labels:</code>
<code> app: myapp</code>
<code> spec:</code>
<code> containers:</code>
<code> - name: nginx</code>
<code> image: nginx:1.19.4</code>
<code> ports:</code>
<code> - containerPort: 80Project Maturity
MetalLB is currently in beta but is already used by many individuals and companies in production and non‑production clusters. No major bugs have been reported based on the frequency of issue reports.
Thank you for reading. If you found this article helpful, feel free to share it with your friends or technical groups.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
DevOps Operations Practice
We share professional insights on cloud-native, DevOps & operations, Kubernetes, observability & monitoring, and Linux systems.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
