MetalLB gives a Kubernetes cluster that runs on bare metal, or on any network without a cloud provider’s load balancer, a working implementation of Service type LoadBalancer. Without it, such a service stays in the pending state because nothing exists to hand out an external address. MetalLB takes addresses from pools the administrator defines, assigns one to each service, and makes the network deliver that address’s traffic to the cluster, using either ARP and NDP at Layer 2 or BGP sessions with nearby routers. The project began as an independent open source effort and was accepted into the CNCF Sandbox on September 14, 2021.
CNCF daily · Sprint 3, post 9 of 21 · Service Proxy
At a glance
| Category | Orchestration & Management › Service Proxy |
| CNCF status | Sandbox. Accepted September 14, 2021 |
| Written in | Go |
| License | Apache 2.0 |
| Core resources | IPAddressPool, L2Advertisement, BGPAdvertisement, BGPPeer |
| Modes | Layer 2 (ARP for IPv4, NDP for IPv6) and BGP |
| Components | A cluster-wide controller that assigns addresses, and a speaker on every node that announces them |
| Install options | Manifests, Helm chart and Kustomize into the metallb-system namespace |
Architecture
flowchart TB
CLIENT[Client<br/>on the site network] ==>|1 packets to service IP| NET[Switch or router]
NET ==>|2 delivered to announcing node| NODE[Cluster node<br/>kube-proxy or CNI]
NODE ==>|3 forwarded to a pod| POD[Backend pod]
USER[Service of type<br/>LoadBalancer] -.->|watched by| CTRL[MetalLB controller]
POOL[IPAddressPool] -.->|address ranges| CTRL
CTRL -.->|assigns external IP<br/>writes service status| USER
SPK[MetalLB speaker<br/>on every node] -.->|reads assignments| CTRL
SPK ==>|ARP and NDP replies<br/>in Layer 2 mode| NET
SPK ==>|BGP routes<br/>in BGP mode| NET
classDef core fill:#0f766e,stroke:#064e4a,stroke-width:2px,color:#ffffff
classDef data fill:#e3f2fd,stroke:#1565c0,stroke-width:1.5px,color:#1d1c1a
classDef actor fill:#eceff1,stroke:#455a64,stroke-width:1.5px,color:#1d1c1a
classDef cfg fill:#ede7f6,stroke:#5e35b1,stroke-width:1.5px,color:#1d1c1a
class CTRL,SPK core
class NODE,POD,NET data
class CLIENT actor
class USER,POOL cfg
Key: teal blocks are MetalLB components, blue are the network and the cluster data path, purple are Kubernetes and MetalLB configuration, grey is the client. Numbers follow a packet; thick arrows carry traffic and announcements, dashed arrows carry control information.
| Component | Responsibility |
|---|---|
| Controller | Watches services of type LoadBalancer and assigns each an address from an IPAddressPool, then records it in the service status. |
| Speaker | Runs on each node and announces assigned addresses to the network, by answering ARP or NDP requests or by speaking BGP. |
| IPAddressPool | Declares the address ranges MetalLB may use and which services may draw from each range. |
| L2Advertisement / BGPAdvertisement | Choose how a pool is announced, and limit the announcement to chosen nodes or interfaces. |
| BGPPeer | Describes a router that nodes peer with, including its address and autonomous system number. |
Design principle. MetalLB does not forward traffic itself. It only gets traffic for an address to a node. From there, kube-proxy or the CNI plugin steers packets to pods, so MetalLB composes with the existing data path rather than replacing it.
Production reference design
A typical edge or on-premises site has three or more nodes and a router or switch pair that the team controls.
- Prepare the cluster. If kube-proxy runs in IPVS mode, enable strict ARP in its configuration, as the MetalLB documentation requires. If the cluster enforces Pod Security Admission, label the
metallb-systemnamespace as privileged, because the speaker needs elevated network privileges. - Install MetalLB with Helm, pinning a stable release rather than a development branch:
helm repo add metallb https://metallb.github.io/metallb helm install metallb metallb/metallb --namespace metallb-system --create-namespace - Define the address pool and the announcement. A Layer 2 example for a small site, with addresses reserved outside the DHCP range:
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: { name: edge-pool, namespace: metallb-system } spec: addresses: ["192.168.10.240-192.168.10.250"] --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: { name: edge-l2, namespace: metallb-system } spec: ipAddressPools: ["edge-pool"] - Expose a service. Create a
Serviceof typeLoadBalancerand confirm that an external address appears in its status, then request it from another machine on the same network. - Move to BGP when needed. Define a
BGPPeerfor the upstream router and aBGPAdvertisementfor the pool, so that every node can attract traffic and the router balances across them. Add BFD where fast failure detection matters.
Typical uses include exposing an ingress controller or gateway on bare-metal clusters, providing stable addresses at edge sites, and giving each cluster in a multi-site design a predictable entry point that a global load balancer such as k8gb can publish through DNS.
Operational considerations
- Layer 2 mode has one active node per address. All traffic for a service enters through a single node, which limits bandwidth to that node and makes failover depend on a new node taking over the address. It needs no router configuration and suits small sites.
- BGP mode spreads traffic across nodes. It needs routers that accept peering from the nodes, and the split depends on the router’s hashing. Existing connections can be disrupted when the set of announcing nodes changes, so plan maintenance accordingly.
- Plan the address ranges. Keep pools outside DHCP ranges and ensure they do not overlap across sites that later interconnect. Editing or deleting a pool can cause assigned addresses to change.
- Check CNI compatibility. Some network plugins also speak BGP or manage the same addresses. Read the compatibility notes for your CNI before enabling BGP mode.
- Secure and observe. The speaker runs privileged, so restrict who can edit the MetalLB resources. Scrape the controller and speaker metrics and alert on services stuck without an address.
Adoption
- MetalLB is widely used on bare-metal and edge clusters, and several Kubernetes distributions document it as their recommended on-premises load-balancer add-on.
- The repository keeps an
ADOPTERS.mdfile where users list themselves. Consult it for current named organisations rather than relying on a fixed list here. - Because the project is at the Sandbox level, treat the CNCF label as an early stage and evaluate its release cadence and issue activity directly.
Alternatives
| Solution | Model | Best suited to |
|---|---|---|
| kube-vip (CNCF Sandbox) | Virtual IP for the control plane and services | Small clusters that also need a highly available API server address |
| Cilium (CNCF Graduated) | Built-in load-balancer IP management and BGP control plane | Clusters already on Cilium that prefer fewer components; see the Cilium brief |
| LoxiLB (CNCF Sandbox) | eBPF-based service load balancer | Edge and telco setups needing high-performance Layer 4 balancing |
| Cloud load balancers | Provider-managed through the cloud controller | Clusters inside a public cloud, where MetalLB is not needed |
| Hardware or external appliances | Dedicated load balancers in front of node ports | Sites with an existing appliance team and fixed procedures |
Strengths and limitations
| Strengths | Limitations |
|---|---|
Brings LoadBalancer services to any bare-metal cluster |
Layer 2 mode sends each address’s traffic through one node |
| Uses standard protocols, with no vendor hardware | BGP mode needs routers that accept peering and careful configuration |
| Declarative configuration through Kubernetes resources | Does not terminate TLS or route by host, so it pairs with an ingress or gateway |
| Works with existing kube-proxy and CNI data paths | Some CNIs conflict in BGP mode |
| Apache 2.0 licence and a long track record on bare metal | Sandbox maturity; some alternatives are bundled with the CNI |
Recommendation
Adopt for bare-metal and edge Kubernetes clusters that need LoadBalancer services and do not already get this from the CNI. Start in Layer 2 mode on a small site to validate address ranges and failover, and move to BGP where traffic volume or fast convergence matter. Clusters on a public cloud should keep the provider’s load balancer, and clusters that already run Cilium with its own load-balancer features should weigh using that instead of adding another component.
References: CNCF project page · MetalLB documentation · MetalLB installation guide · MetalLB repository · CNCF Landscape