For the complete documentation index, see llms.txt. This page is also available as Markdown.

How to Expose a Kubernetes MetalLB Load Balancer in a Virtual Network

Problem

How do you make a MetalLB load balancer service in a PCD-K cluster reachable from outside the cluster's virtual (tenant) network?

By default, MetalLB assigns external IPs from an address pool within the cluster's virtual network. Those IPs are not directly routable from the physical network. To expose a service externally, you must bridge the virtual and physical networks using OpenStack floating IPs.

Environment

  • Platform9 Private Cloud Director (PCD) with PCD-K clusters deployed on virtual (Neutron) networks

  • MetalLB add-on enabled on the cluster (L2 mode)

  • An OpenStack router connecting the virtual network to the physical/external network

How it works

The virtual and physical networks do not connect at Layer 2. OpenStack bridges them at Layer 3 using NAT via a floating IP:

Component
Network
Role

Floating IP (e.g. 10.10.17.140)

Physical / provider

Neutron port on external network; the public address

Fixed port (e.g. 192.168.1.233)

Virtual / tenant

Reserves the MetalLB VIP in IPAM; anchors the floating IP

Floating IP association

Router

DNAT 10.10.17.140192.168.1.233, SNAT on return

When a packet reaches the physical floating IP, the Neutron router DNATs it to the virtual network IP. MetalLB (in L2 mode) makes a worker node answer ARP for that IP on the tenant network. kube-proxy on that node then forwards the packet to the target pod.

The Expose LB configuration in PCD handles the OpenStack port security requirements that allow MetalLB's L2 ARP announcements to work on Neutron.

Procedure

Prerequisites

  • MetalLB add-on is enabled on the cluster and Expose LB is configured with the MetalLB VIP in the Allowed Addresses field. See Set up Load Balancers using MetalLB. Wait for all worker nodes to return to Ready before proceeding.

  • The MetalLB VIP must be in the same subnet as the worker nodes. MetalLB L2 mode relies on ARP, which is scoped to a single broadcast domain — if the VIP is in a different subnet, the Neutron router will never ARP for it on the worker node segment and the service will be unreachable.

  • A virtual network IP from the worker nodes' subnet (e.g. 192.168.1.233) is reserved for the MetalLB VIP — it must not conflict with existing VM IPs, podCIDR, or serviceCIDR.

  • An OpenStack router is already configured to connect the virtual network to the physical/external network.

  • You have OpenStack CLI access (openstack CLI or equivalent API access).

Step 1: Configure the MetalLB IPAddressPool and L2Advertisement

Apply an IPAddressPool containing the virtual network IP and a corresponding L2Advertisement in the cluster:

Step 2: Create an OpenStack port for the MetalLB VIP

This port reserves the VIP in Neutron's IPAM and provides an attachment point for the floating IP.

Note the port UUID from the output — you will need it in the next step.

Step 3: Assign a floating IP to the MetalLB VIP port

Map an existing floating IP (or allocate a new one) to the port created in the previous step:

Assigning a floating IP to an unbound port (one not attached to a VM) is currently only possible via the OpenStack CLI or API. UI support is planned.

Step 4: Deploy a service and verify

Create a LoadBalancer service in the cluster. MetalLB should assign the VIP from the pool:

Confirm the external IP is assigned:

Test access via the floating IP from outside the virtual network:

Additional Information

  • The floating IP to port association (Step 3) is currently only possible via the OpenStack CLI.

Last updated