# Set up Load balancers using MetalLB

### Overview

MetalLB provides load balancing for Kubernetes clusters running on bare metal or private cloud infrastructure. By default, load balancer services are not reachable from outside the cluster because egress packets are dropped by security groups. Without the Expose LB feature, you would need to manually allow traffic from the external IP pool specified in the MetalLB address pool, or create a custom security group with the required ingress ports open.

The Expose LB feature simplifies this by letting you configure allowed addresses and inbound ports in one place, eliminating the need to edit security groups on individual worker nodes.

#### Prerequisites

MetalLB add-on is enabled during cluster creation.

{% hint style="info" %}
The **Expose LB** feature is enabled only if the MetalLB add-on was enabled during cluster creation.
{% endhint %}

#### Configure MetalLB load balancing

1. Navigate to **Infrastructure** > **Clusters**.
2. Select the cluster you want to configure.
3. Select **Expose LB**.
4. In the **Allowed Addresses** field, specify the IP addresses or CIDR ranges that MetalLB can assign to load balancer services. Enter either a specific IP address or a CIDR range from your MetalLB address pool. You should ensure that the IP addresses or CIDR range does not conflict with:
   1. The `serviceCIDR` (`10.96.0.0./16`)
   2. The `podCIDR` (`10.244.0.0/16`)
   3. The worker node IPs in your environment

The following examples show valid IP address formats:

Single IP address:

```
   10.10.0.5
```

CIDR range:

```
   10.10.62.0/24
```

{% hint style="warning" %}
Modifying the Allowed Addresses field triggers a restart of existing worker nodes.
{% endhint %}

5. In the **Inbound Port Details** section, define the ports and protocols that external services can use to communicate with your cluster.

   <table><thead><tr><th width="190.5390625">Field</th><th>Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>Identifier for the port rule. Must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.</td><td><code>custom-load-balancer</code></td></tr><tr><td><strong>Port</strong></td><td>Port number or range for external traffic.</td><td><code>80</code> or <code>3000-3500</code></td></tr><tr><td><strong>Protocol</strong></td><td>Network protocol. Select <strong>TCP</strong> or <strong>UDP</strong>.</td><td><code>TCP</code></td></tr><tr><td><strong>IP Address or CIDR</strong></td><td>Source IP address or subnet allowed to send traffic through this port.</td><td><code>10.10.0.7</code> or <code>10.10.0.0/9</code></td></tr></tbody></table>
6. Select **Submit**.

### Set up MetalLB with L2 mode&#x20;

In your Kubernetes cluster, create a corresponding `IPAddressPool` and `L2Advertisement` resource. For example:

<pre><code>apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
  # Note: This is the allocatable range of IPs from your address pool. 
<strong>  - 10.10.62.1-10.10.62.254
</strong></code></pre>

```
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default-l2
  namespace: metallb-system
spec:
  ipAddressPools:
  - default-pool
```

### Set up MetalLB with BGP Mode

Setting up MetalLB with BGP support requires in integration into the networking infrastructure like router configurations. Unfortunately router configurations differ between different vendors.&#x20;

For the BGP mode to be correctly configured, MetalLB often requires a `IPAddressPool` , a `BGPPeer` and a `BGPAdvertisement` custom resource to be applied similar to the L2 mode.&#x20;

### Verify load balancer service works

Create an nginx deployment and expose it via a `loadbalancer` service:

```
$ kubectl create deployment nginx --image=nginx
$ kubectl expose deployment nginx \
  --port=80 --target-port=80 \
  --type=LoadBalancer \
  --name=nginx-lb
```

Get the service IP:

```
$ kubectl get svc nginx-lb  
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
nginx-lb   LoadBalancer   10.96.130.137   10.10.63.241   80:32456/TCP   5h33m
```

Use `curl` to get the default nginx page:

```
$ curl 10.10.63.241:80 -I
HTTP/1.1 200 OK
Server: nginx/1.29.6
Date: Mon, 23 Mar 2026 16:30:44 GMT
Content-Type: text/html
Content-Length: 896
Last-Modified: Tue, 10 Mar 2026 15:29:07 GMT
Connection: keep-alive
ETag: "69b038c3-380"
Accept-Ranges: bytes
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.platform9.com/private-cloud-director/kubernetes-clusters/pcd-kubernetes-clusters/set-up-load-balancers-using-metallb.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
