How to Set Up MetalLB for Load Balancing on Bare Metal Kubernetes

MetalLB Bare Metal load balancing

How to Set Up MetalLB for Load Balancing on Bare Metal Kubernetes

In a cloud environment, exposing applications with LoadBalancer services is easy because the cloud provider automatically creates an external load balancer for you. On Bare Metal Kubernetes clusters, they don’t work, and services stay pending. MetalLB Bare Metal load balancing fixes this by enabling service type as a load balancer without any cloud provider.

In this guide, you will learn to plan your IP ranges, configure Layer 2 and BGP modes, and test your setup with a sample application.

You can deploy MetalLB on PerLod Hosting high‑performance bare metal servers for more stable networking and throughput.

Prerequisites and Network Planning for MetalLB Bare Metal Load Balancing

Before you start to deploy MetalLB, you should confirm a few cluster and network details.

  • Kubernetes 1.13+ with a CNI plugin that does not conflict with MetalLB, such as Calico, Flannel, Cilium, etc.
  • A bare metal cluster where the cloud load balancer integration is not available, like kubeadm, k3s, k0s, etc.
  • A dedicated pool of external IPs in your LAN or a separate subnet that MetalLB can assign to LoadBalancer services.

For example, if your LAN is 192.168.1.0/24, you might reserve 192.168.1.240–192.168.1.250 only for MetalLB.

Note: Do not assign MetalLB IPs to any physical hosts or DHCP pools.​

MetalLB can be installed in several ways, including:

  • Apply upstream Kubernetes manifests directly.
  • Install via Helm using the official Helm repository.
  • Use Kustomize overlays for more custom deployments.

The manifest and Helm methods are the most common methods, which will be explained in this guide.

Method 1. Install MetalLB with Kubernetes Manifest

The easiest way to install MetalLB is with a single command that downloads official Kubernetes files. This method works on any cluster and sets up MetalLB’s main parts, including:

  • The metallb-system namespace, if it is not precreated.​
  • The MetalLB controller Deployment and speaker DaemonSet, responsible for assigning IPs and announcing them on the network.​
  • CRDs such as IPAddressPool and L2Advertisement or BGP‑related resources are used for configuration.

No additional tools are needed for this method; you only require kubectl.

Create MetalLB Namespace (Optional)

The first step is to create the MetalLB Namespace.

Some examples and older docs apply a separate namespace manifest first, but the current native manifest usually includes namespace creation.

If you want to create it, you can use the command below:

kubectl create namespace metallb-system

It tells the Kubernetes API server to create a logical namespace called metallb-system where all MetalLB resources will live.

Then, if you apply the native manifest, it will install the controller and speaker components and their CRDs.

Apply MetalLB Native Kubernetes Manifest

From the official website, use the latest version and apply the MetalLB manifest with the command below:

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

This asks Kubernetes to create or update all objects defined in the manifest at that URL.

Verify MetalLB Pods

Once you are done, check that the controller and speaker pods are running with the command below:

kubectl get pods -n metallb-system

You should see one controller pod and one speaker pod per node. Also, the status should be Running, and READY should be 1/1 for each pod.

If pods are not ready, check events with:

kubectl describe pod -n metallb-system <pod-name>
kubectl logs -n metallb-system <pod-name>

These commands show why a pod is failing as image pull error, permission, etc.

Method 2. Install MetalLB with Helm

Another method that you can use to install MetalLB is using Helm. Helm is recommended for production because it makes upgrades and customization easier.

Add MetalLB Helm Repository

You can use the command below to add the MetalLB Helm Repository, which registers the official MetalLB chart repository under the name metallb so Helm can fetch charts from it:

helm repo add metallb https://metallb.github.io/metallb

Then, update the index of all configured repositories with:

helm repo update

Install MetalLB Helm Chart

Use the command below to install a new Helm release called metallb using the metallb chart from the metallb repo:

helm install metallb metallb/metallb -n metallb-system --create-namespace

Options explanations:

  • -n metallb-system: Deploys all components into the metallb-system namespace.​
  • –create-namespace: Creates the namespace if it doesn’t exist.

Note: You can also provide a custom values.yaml to tune settings, such as enabling FRR mode for advanced BGP use cases.

MetalLB IP Pools and Advertisements

MetalLB does nothing until you define IP pools and how to advertise them. Here are the core concepts in MetalLB:

1. IPAddressPool: Defines a range of IPs that MetalLB can assign to services.​

2. L2Advertisement: Tells MetalLB to announce those IPs on the network using Layer 2 (ARP for IPv4, NDP for IPv6).​

3. BGP resources (like BGPPeer, BGPAdvertisement) are used when running MetalLB in BGP mode and define router peers, ASNs, and advertised prefixes.

1. Configure MetalLB in Layer 2 Mode

The simplest starting point is Layer 2 mode. It works on almost any Ethernet LAN and does not require a BGP‑capable router.

Create an IPAddressPool:

The first step is to create an IPAddressPool YAML file, for example, metallb-ipaddresspool-l2.yaml.

Add the following content to the file:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: l2-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.1.240-192.168.1.250

Command explanation:

  • apiVersion: metallb.io/v1beta1 and kind: IPAddressPool: Use the MetalLB CRD that defines IP ranges.​
  • metadata.name: l2-pool: A logical name for this pool; you will reference it elsewhere if needed.​
  • namespace: metallb-system: Must match the namespace where MetalLB is installed.​
  • spec.addresses: A list of ranges or CIDRs.

Then, apply it with the command below:

kubectl apply -f metallb-ipaddresspool-l2.yaml

Create an L2Advertisement:

The next step is to create another YAML file for L2Advertisement, for example, metallb-l2advertisement.yaml.

Add the following content to the file:

apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - l2-pool
  • kind: L2Advertisement: Configures how IPs from the referenced pools are announced at Layer 2.​
  • ipAddressPools: References the IP pool by name l2-pool, ensuring MetalLB will advertise those IPs via ARP/NDP.​

Apply this with the command below:

kubectl apply -f metallb-l2advertisement.yaml

Now MetalLB is ready to allocate IPs from the IP ranges to LoadBalancer services and announce them on the LAN.

Testing MetalLB with a Sample Service:

You can deploy a sample service to test that MetalLB is working correctly. For example, create an Nginx test deployment file nginx-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-test
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-test
  template:
    metadata:
      labels:
        app: nginx-test
    spec:
      containers:
        - name: nginx
          image: nginx:stable
          ports:
            - containerPort: 80

Apply it with the command below:

kubectl apply -f nginx-deployment.yaml

This creates a Deployment called nginx-test with two replicas running the standard Nginx container on port 80.

Next, you must expose the deployment as a LoadBalancer. Create the nginx-service-lb.yaml file:

apiVersion: v1
kind: Service
metadata:
  name: nginx-lb
spec:
  type: LoadBalancer
  selector:
    app: nginx-test
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP

Apply the config with the command below:

kubectl apply -f nginx-service-lb.yaml

Now check the assigned external IP:

kubectl get svc nginx-lb

You should see EXTERNAL-IP populated with one of the IPs from the IP ranges after a few seconds.

Access the External IP from your LAN, and you must see the default Nginx page.

http://<EXTERNAL-IP>/

If the EXTERNAL-IP remains pending, check:

kubectl get pods -n metallb-system #MetalLB pods status
kubectl describe svc nginx-lb      #Events on the service for allocation errors

2. Configure MetalLB in BGP Mode

BGP mode scales better and integrates with routing on your firewall or router, but it requires BGP‑capable hardware or software, for example, a router, FRR, or a firewall like pfSense or OPNsense.

Plan for BGP:

For a basic BGP configuration, you need:

  • An IP address of your router, for example, 10.0.0.1.
  • The router’s ASN, for example, 64501.
  • An ASN for MetalLB itself, for example, 64500.
  • An IP prefix (subnet) MetalLB will advertise, for example, 10.25.0.0/24.

This subnet should not be configured anywhere else; it will be announced dynamically by MetalLB and routed to your nodes.

Example BGP Configuration CRs:

A typical BGP setup includes an IPAddressPool, a BGPPeer, and a BGPAdvertisement. The older ConfigMap‑based style might look like this:

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    peers:
      - peer-address: 172.17.9.200
        peer-asn: 64512
        my-asn: 64513
    address-pools:
      - name: default
        protocol: bgp
        addresses:
          - 10.25.0.10-10.25.3.250

Note: Newer versions of MetalLB prefer CRDs like BGPPeer and BGPAdvertisement instead of a single config ConfigMap.

For larger, routed environments, combine MetalLB with enterprise‑grade dedicated servers to handle higher traffic and more BGP sessions.

Which MetalLB mode should we use? Layer 2 or BGP?

Layer 2 is simpler and works on almost any home or small office network, while BGP is more advanced and designed for larger, routed environments.

Here is a quick comparison to choose the right mode:

FeatureLayer 2 ModeBGP Mode
Network requirementAny Ethernet network, no special router.​BGP‑capable router/firewall or software router.​
How it worksOne node advertises VIP via ARP/NDP.​Nodes announce VIPs as routes via BGP.
Load distributionAll traffic enters via one node, then kube-proxy is distributed.​Traffic can be balanced at the routing layer across nodes.​
ComplexitySimple to set up (Pools + L2Advertisement).​More complex (ASNs, peers, prefixes).​
Best forSmall/medium labs, simple homelab clusters.​Larger production clusters need advanced routing.​

FAQs

What problem does MetalLB solve on bare‑metal Kubernetes?

MetalLB gives you working LoadBalancer services on clusters that have no cloud provider. Instead of services staying in a pending state, MetalLB assigns real IPs from your network so you can reach apps directly.

Do I need a special router to use MetalLB?

No. For Layer 2 mode, you only need a normal Ethernet network and a free IP range. For BGP mode, you do need a BGP‑capable router, firewall, or software router.

Is MetalLB safe to use in production?

Many users run MetalLB in production, but you should treat it like any core network component. Also, make sure your IP planning and routing are correct before going live.

Does MetalLB replace Ingress controllers?

No. MetalLB provides external IPs for Services. Ingress controllers like NGINX Ingress or Traefik still handle HTTP routing and host or path rules.

Conclusion

MetalLB provides cloud-style load balancing to bare metal Kubernetes by turning ordinary Services into reachable endpoints on your own network. With an IP plan and a few YAML objects, you can choose between a simple Layer 2 setup for homelabs or a powerful BGP configuration for routed environments.

We hope you enjoy the MetalLB Bare Metal load balancing setup guide.

Subscribe to our X and Facebook channels to get the latest articles and updates.

For further reading:

VPS Snapshots and Disaster Recovery Strategies

Setting Up Docker Swarm on VPS Clusters

Post Your Comment

PerLod delivers high-performance hosting with real-time support and unmatched reliability.

Contact us

Payment methods

payment gateway
Perlod Logo
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.