
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Running Kubernetes on self-managed hardware means you lose the automatic load balancer provisioning that cloud providers handle silently. MetalLB: Load Balancing for bare metal solves this gap by implementing a network load balancer natively within your cluster, assigning real IP addresses from your local subnet to Services of type LoadBalancer. Whether you are running a home lab, an edge deployment in Nepal, or an enterprise on-prem data center, understanding how to configure and troubleshoot MetalLB is essential for making your services accessible without manual NodePort management.
How does MetalLB: Load Balancing for bare metal actually work?
MetalLB is not a traditional load balancer like HAProxy or Nginx that proxies traffic at the application layer. Instead, it is a control-plane component that manipulates network protocols to direct traffic to your nodes. Understanding this distinction prevents most configuration errors I see in production audits. When you create a Service with type: LoadBalancer, MetalLB allocates an IP from a configured pool and announces it to the network so clients can reach it directly.
The system consists of two components: the controller (a Deployment) that manages IP allocation and validates configuration, and the speaker (a DaemonSet) that runs on every node and speaks the network protocol. In Layer 2 mode, the speaker uses ARP (IPv4) or NDP (IPv6) to respond to address resolution requests, effectively telling the network "I am that IP." Only one speaker acts as the leader per service IP to avoid duplicate responses. In BGP mode, all speakers establish peering sessions with your upstream routers and advertise the IP prefix, enabling ECMP (Equal-Cost Multi-Path) routing for true load distribution across nodes.
This architecture means MetalLB does not touch your data path. Once the IP is announced, packets flow through standard Linux networking and Kubernetes ingress controllers or kube-proxy rules. This separation is why MetalLB is so lightweight but also why debugging requires understanding both Kubernetes and your underlying network topology.
How do you install and configure MetalLB in Layer 2 mode?
Layer 2 mode is the default choice for most bare metal deployments because it requires no special router configuration. It works on any flat network where your nodes and clients share the same broadcast domain. For teams deploying K3s on edge hardware or single-subnet environments, this is usually the right starting point.
Install MetalLB via Helm
Helm is the recommended installation method in 2026. The official chart handles CRDs, RBAC, and speaker scheduling correctly:
helm repo add metallb https://metallb.github.io/metallb
helm repo update
helm install metallb metallb/metallb \
--namespace metallb-system \
--create-namespace \
--version 0.14.9 Wait for the speaker pods to reach Ready state before proceeding. Speakers require hostNetwork: true and specific capabilities (CAP_NET_ADMIN, CAP_NET_RAW), so verify they are not blocked by PodSecurityAdmission policies if you have strict enforcement enabled.
Define an IPAddressPool and L2Advertisement
MetalLB v0.13+ separated IP pools from advertisement configuration. Create a pool with IPs from your local subnet that are outside your DHCP range to prevent conflicts:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: production-pool
namespace: metallb-system
spec:
addresses:
- 192.168.10.200-192.168.10.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2-advert
namespace: metallb-system
spec:
ipAddressPools:
- production-pool A common mistake is overlapping the pool with existing static IPs or DHCP leases. Always reserve these addresses in your router or DHCP server first. In Nepali ISP environments where static IP blocks are small, coordinate with your network admin to carve out a dedicated range specifically for MetalLB.
When should you use BGP mode instead of Layer 2?
Layer 2 mode has a fundamental limitation: only one node receives traffic for a given service IP. If that node fails, there is a brief outage while ARP caches expire and the new leader announces itself. BGP mode eliminates this single-point-of-failure by advertising the IP from all nodes simultaneously, letting your upstream router distribute traffic via ECMP.
Choose BGP when you need high availability without client-side retry delays, when your cluster spans multiple subnets, or when you want to integrate with existing enterprise routing infrastructure. The tradeoff is complexity: you must configure BGP peers on your routers (Cisco, Juniper, MikroTik, or FRR-based Linux boxes). For guidance on securing the underlying network, review Ubuntu security hardening since MetalLB speakers run with elevated network privileges.
Configure BGP Peering
Define your BGP peers and associate them with an IP pool. This example assumes your router AS is 64512 and your cluster uses AS 64513:
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
name: core-router
namespace: metallb-system
spec:
myASN: 64513
peerASN: 64512
peerAddress: 192.168.1.1
passwordSecret:
name: bgp-secret
key: password
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: bgp-advert
namespace: metallb-system
spec:
ipAddressPools:
- production-pool
peers:
- core-router Store BGP passwords in Kubernetes Secrets, never in plaintext manifests. If you are managing secrets across environments, consider proper secrets management practices to avoid leaking credentials during GitOps syncs.
How do you troubleshoot MetalLB when services stay Pending?
The most frequent issue I encounter is Services stuck in <pending> EXTERNAL-IP state. This almost always stems from misconfiguration rather than bugs. Follow this diagnostic sequence:
- Verify pool assignment: Run
kubectl get ipaddresspools -n metallb-systemand confirm the pool exists and has available addresses. Check events withkubectl describe svc <service-name>— MetalLB emits clear events when allocation fails. - Check speaker status:
kubectl get pods -n metallb-systemshould show all speakers Running. CrashLoopBackOff usually indicates missing capabilities or SELinux/AppArmor denials. Check logs withkubectl logs -n metallb-system -l app=metallb -c speaker. - Validate network connectivity: In L2 mode, test ARP from another machine:
arping -I eth0 192.168.10.200. No response means the speaker isn't binding to the correct interface. Use themetallb.universe.tf/address-poolannotation to force a specific pool if you have multiple. - Inspect BGP sessions: In BGP mode, check peer status via router CLI or MetalLB metrics. Sessions stuck in Active/Connect state indicate firewall blocks (TCP 179) or ASN mismatches. Enable debug logging temporarily by setting
--log-level=debugon the speaker. - Review admission webhooks: MetalLB v0.14+ includes validating webhooks that reject invalid configs. If
kubectl applyfails silently, checkkubectl get validatingwebhookconfigurationsand ensure the webhook service is reachable.
A subtle gotcha in 2026: some CNI plugins (especially Cilium in strict mode) intercept ARP/NDP before MetalLB can respond. If you use Cilium with eBPF, verify that L2 announcements are compatible with your chaining configuration or switch to BGP mode which operates independently of CNI datapath interception.
MetalLB vs alternatives: Which load balancer fits your bare metal cluster?
MetalLB is not the only option for bare metal load balancing. Choosing the wrong tool leads to operational debt. Here is how the main contenders compare in production:
| Feature | MetalLB | Kube-VIP | Ingress-Nginx + NodePort | HAProxy External |
|---|---|---|---|---|
| Service Type Support | LoadBalancer native | LoadBalancer + Control Plane | NodePort only | External LB required |
| BGP Support | Yes (full) | Limited | No | N/A |
| ECMP Multi-path | Yes | No | No | Depends on HW |
| Complexity | Low-Medium | Medium | Low | High |
| Data Path Proxy | No (announce only) | No (announce only) | Yes (L7) | Yes (L4/L7) |
| Best For | General purpose LB | HA Control Plane + Simple LB | Dev/Test clusters | Legacy compliance |
In practice, MetalLB covers 90% of bare metal use cases. Kube-VIP shines when you also need control plane HA (VIP for API server) and want a single tool. External HAProxy makes sense only when compliance mandates physical appliance separation or when you need advanced L7 features MetalLB doesn't provide. Avoid NodePort-only setups in production — they expose non-standard ports, complicate firewall rules, and make DNS management painful.
Production Checklist for MetalLB on Bare Metal
Before declaring your MetalLB deployment production-ready, verify these items. Skipping them causes outages during upgrades or node maintenance:
- Reserve IPs externally: Document and reserve your MetalLB pool in your IPAM system, router config, and DHCP server. Duplicate IP assignment is the #1 cause of intermittent connectivity issues.
- Monitor speaker health: Expose Prometheus metrics (
/metricson port 7472) and alert onmetallb_speaker_announced == 0for critical services. Integrate with your monitoring stack to catch silent failures. - Test failover: Regularly cordon/drain nodes and verify IP migration completes within acceptable SLA. In L2 mode, expect 10-30 second disruption; in BGP, sub-second. Document actual recovery times for your SLOs.
- Pin versions: MetalLB upgrades occasionally change CRD schemas. Always read release notes and test in staging. Use ArgoCD or Flux to manage upgrades declaratively and enable rollback.
- Secure the namespace: Restrict RBAC in
metallb-system. Speakers run privileged — limit who can modify IPAddressPools or BGPPeers. Audit changes via policy-as-code tools like OPA/Gatekeeper.
Making MetalLB Work Reliably in Your Environment
MetalLB: Load Balancing for bare metal transforms self-managed Kubernetes from a networking headache into a platform that behaves like the cloud. Start with Layer 2 for simplicity, graduate to BGP when your availability requirements demand it, and always validate your network assumptions before going live. The key insight is that MetalLB is a protocol announcer, not a proxy — understanding this mental model makes troubleshooting intuitive rather than mysterious.
If you are designing a bare metal or hybrid Kubernetes platform and need help getting MetalLB, networking, or compliance right the first time, reach out to discuss your architecture. Getting the load balancing layer wrong early creates technical debt that compounds with every new service you deploy.