Skip to main content

MetalLB — Real LoadBalancer IPs on Bare-Metal

On cloud providers (AWS, GCP, Azure) when you create a Kubernetes Service of type LoadBalancer, the cloud automatically provisions a load balancer with a real IP. On bare-metal, this does nothing — services stay in <pending> state forever.

MetalLB fixes this by assigning real IPs from your local network to LoadBalancer services.


How It Works

kubectl expose deployment my-app --type=LoadBalancer --port=80


MetalLB assigns: 10.0.0.200


Any machine on 10.0.0.0/24 can reach:
http://10.0.0.200:80 → my-app

MetalLB announces the IP via ARP (Layer 2 mode) so the network switch routes traffic correctly.


Install MetalLB

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

Wait for pods:

kubectl get pods -n metallb-system --watch

Configure IP Address Pool

Define a range of IPs MetalLB can hand out — these must be in your 10.0.0.0/24 subnet and not assigned to anything else:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: cluster-pool
namespace: metallb-system
spec:
addresses:
- 10.0.0.200-10.0.0.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: cluster-l2
namespace: metallb-system
spec:
ipAddressPools:
- cluster-pool
kubectl apply -f metallb-config.yaml

Test It

kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --type=LoadBalancer --port=80
kubectl get svc nginx

Expected output:

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
nginx LoadBalancer 10.96.12.34 10.0.0.200 80:31234/TCP

EXTERNAL-IP is no longer <pending> — it has a real IP.

curl http://10.0.0.200
# → nginx welcome page

Via Tailscale (subnet route advertised), this works from any remote machine too.


Assigned IP Pool Plan

RangeUse
10.0.0.1MAAS Controller
10.0.0.2–10.0.0.10Cluster nodes (MAAS DHCP)
10.0.0.200–10.0.0.250MetalLB LoadBalancer pool

Done When

✔ MetalLB pods Running
✔ IPAddressPool and L2Advertisement applied
✔ LoadBalancer service gets a 10.0.0.200+ IP
✔ Service reachable directly by IP