Skip to main content
This guide walks you through installing MetalLB, a load balancer implementation for bare metal Kubernetes clusters, on your Talos cluster.

What is MetalLB?

MetalLB is a network load balancer implementation for Kubernetes clusters that don’t run on supported cloud providers. It provides:
  • LoadBalancer service type support for bare metal clusters
  • Automatic IP address assignment from configured pools
  • Layer 2 (ARP/NDP) mode for simple network integration
  • BGP mode for advanced routing scenarios
  • Multiple IP address pools for different services or tenants
  • Cloud-provider parity bringing the LoadBalancer experience to on-premises clusters
Unlike cloud load balancers, MetalLB runs entirely within your cluster and announces IP addresses to your local network.

Prerequisites

Before installing MetalLB, you need to:
  1. Have a running Talos Kubernetes cluster (see the deployment guide)
  2. Have kubectl configured to access your cluster
  3. Have helm installed on your local machine
  4. Know your available IP address range for load balancer services
Important network considerations:
  • You need a range of IP addresses on your local network that are not used by DHCP
  • These IPs must be in the same subnet as your cluster nodes

Configure Namespace Security

MetalLB requires privileged access to manage network interfaces and announce IP addresses at the system level. We need to configure the namespace with appropriate Pod Security Standards. What are Pod Security Standards? Kubernetes Pod Security Standards define three policies:
  • Privileged: Unrestricted policy (required for system-level operations)
  • Baseline: Minimally restrictive policy
  • Restricted: Heavily restricted policy (most secure)
MetalLB needs privileged access because it:
  • Manipulates network interfaces and ARP/NDP tables
  • Manages BGP sessions with network routers
  • Performs low-level networking operations
  • Interacts directly with the kernel networking stack
Create the namespace with security labels:
kubectl create namespace metallb-system

kubectl label namespace metallb-system \
  pod-security.kubernetes.io/enforce=privileged \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/audit=privileged \
  pod-security.kubernetes.io/audit-version=latest \
  pod-security.kubernetes.io/warn=privileged \
  pod-security.kubernetes.io/warn-version=latest
What each label means:
  • enforce=privileged: Pods violating this policy will be rejected
  • audit=privileged: Policy violations are logged to the audit log
  • warn=privileged: Users receive warnings for policy violations
  • version=latest: Use the latest version of the policy standard

Add MetalLB Helm Repository

MetalLB is distributed via Helm charts, which are packages for Kubernetes applications.
# Add the MetalLB Helm repository
helm repo add metallb https://metallb.github.io/metallb

# Update your local Helm chart repository cache
helm repo update

# Verify the repository was added
helm search repo metallb
Expected output:
NAME              CHART VERSION   APP VERSION   DESCRIPTION
metallb/metallb   0.15.3          v0.15.3       A network load-balancer implementation for Kub...

Install MetalLB

Now we’ll install MetalLB. The installation happens in two phases: first the controller and speaker components, then the configuration. Install MetalLB:
helm install metallb metallb/metallb \
  --namespace metallb-system \
  --version v0.15.3
What gets installed:

MetalLB Controller

  • Watches for Service objects with type: LoadBalancer
  • Assigns IP addresses from configured pools
  • Manages the overall state of load balancer assignments
  • Runs as a Deployment (single instance with leader election)

MetalLB Speaker

  • Announces assigned IP addresses to the network
  • Runs as a DaemonSet (one pod per node)
  • Handles Layer 2 (ARP/NDP) or BGP announcements
  • Responds to ARP requests for assigned IPs
Installation process takes 1-2 minutes. Helm will:
  1. Create CustomResourceDefinitions (CRDs) for MetalLB objects
  2. Deploy the MetalLB controller
  3. Deploy the MetalLB speaker DaemonSet on each node
  4. Set up RBAC permissions
  5. Create webhook configurations

Configure MetalLB

MetalLB requires configuration to know which IP addresses to use. This is done through two custom resources: IPAddressPool and L2Advertisement. Create a configuration file metallb-config.yaml:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.240-192.168.1.250  # Replace with your IP range
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default-l2
  namespace: metallb-system
spec:
  ipAddressPools:
  - default-pool
What these resources mean:

IPAddressPool

  • Defines a pool of IP addresses MetalLB can assign
  • addresses: List of IP ranges or CIDR blocks
    • Example range: 192.168.1.240-192.168.1.250 (11 IPs)
    • Example CIDR: 192.168.1.240/28 (16 IPs)
  • You can create multiple pools for different purposes
  • Replace the example IPs with your actual available range

L2Advertisement

  • Tells MetalLB to advertise IPs using Layer 2 protocols (ARP/NDP)
  • ipAddressPools: Which IP pools to advertise via Layer 2
  • Layer 2 mode is simpler but all traffic goes through one node
  • For production, consider BGP mode for better load distribution
Apply the configuration:
kubectl apply -f metallb-config.yaml
Understanding IP Pool Selection:
  • Choose IPs in the same subnet as your nodes
  • Ensure they’re outside your DHCP range
  • Reserve enough IPs for your expected services
  • Common practice: Use the high end of your subnet (e.g., .240-.250)

Verify Installation

Check pod status:
kubectl get pods -n metallb-system
Expected output (wait until all pods show Running):
NAME                                  READY   STATUS    RESTARTS   AGE
metallb-controller-...                1/1     Running   0          2m
metallb-speaker-...                   1/1     Running   0          2m
metallb-speaker-...                   1/1     Running   0          2m
Verify configuration:
# Check IP address pools
kubectl get ipaddresspools -n metallb-system

# Check L2 advertisements
kubectl get l2advertisements -n metallb-system
Expected output:
NAME           AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
default-pool   true          false             ["192.168.1.240-192.168.1.250"]

NAME        IPADDRESSPOOLS    IPADDRESSPOOL SELECTORS   INTERFACES
default-l2  ["default-pool"]

How to Use MetalLB

Now you can create LoadBalancer services in your cluster:
apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  type: LoadBalancer  # This triggers MetalLB
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: my-app
MetalLB will automatically:
  1. Assign an IP from your configured pool
  2. Announce that IP via Layer 2 (ARP/NDP)
  3. Route traffic to your service’s pods
  4. Update the service with the EXTERNAL-IP
You now have cloud-like LoadBalancer services on your bare metal cluster! 🎉

Request Specific IP

You can request a specific IP address:
apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  type: LoadBalancer
  loadBalancerIP: 192.168.1.241  # Must be in a configured pool
  # ...