Advanced L2 configuration
Limiting the set of nodes where the service can be announced from
In L2 mode, only one node is elected to announce the IP from.
Normally, all the nodes where a Speaker is running are eligible for any given IP.
There can be scenarios where only a subset of the nodes are exposed to a given network, so it can be useful to limit only those nodes as potential entry points for the service IP.
This is achieved by using the node selector in the L2Advertisement CR.
graph TD
metallBA-->|announces|subnetA(Subnet A)
metallBB-->|announces|subnetA(Subnet A)
metallBC-->|announces|subnetB(Subnet B)
subgraph NodeA
metallBA("MetalLB<br>Speaker")
end
subgraph NodeB
metallBB("MetalLB<br>Speaker")
end
subgraph NodeC
metallBC("MetalLB<br>Speaker")
end
In this example, NodeA and NodeB are exposed to the subnet A, whereas node C is exposed to subnet B.
In order to limit the set of nodes for a given advertisement, the node selector must be set:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
nodeSelectors:
- matchLabels:
kubernetes.io/hostname: NodeA
- matchLabels:
kubernetes.io/hostname: NodeBapiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- second-pool
nodeSelectors:
- matchLabels:
kubernetes.io/hostname: NodeCIn this way, all the IPs coming from first-pool will be reachable only via NodeA
and NodeB, and only one of those node will be chosen to expose the IP.
On the other hand, IPs coming from second-pool will be exposed always via NodeC.
Prefer specific nodes for L2 announcements
nodeSelectors is a hard filter: nodes outside the selector cannot announce at all. When you
want a soft preference instead, for example “announce from the edge nodes when possible, fall
back to workers otherwise”, use preferredNodeSelectors. Weights must be in the range 1-100.
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: prefer-edge
namespace: metallb-system
spec:
ipAddressPools:
- production-pool
preferredNodeSelectors:
- weight: 100
preference:
matchLabels:
node-role: edgeNodes matching node-role: edge score 100 and win the election. All other nodes score 0 and
serve as failover when no preferred node is available. Within the same score, the usual
sha256(node + "#" + ip) hash decides, so ordering is deterministic.
Weights can be combined. A node matching multiple selectors sums their weights, and multiple
L2Advertisement objects targeting the same pool sum per-ad scores for a service.
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: tiered-zones
namespace: metallb-system
spec:
ipAddressPools:
- production-pool
preferredNodeSelectors:
- weight: 100
preference:
matchLabels:
zone: primary
- weight: 50
preference:
matchLabels:
zone: secondaryPreferences are scoped to the advertisement’s own nodeSelectors. An ad with no
nodeSelectors scores every node. An ad with nodeSelectors never raises the score of nodes
outside its eligible set.
Weights also sum across separate L2Advertisement objects targeting the same pool. The
example below gives zone: primary an extra 60 on top of any score from prefer-edge, so a
node that is both an edge node and in the primary zone scores 160 and wins over an edge-only
node (100) or a primary-only node (60).
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: zone-boost
namespace: metallb-system
spec:
ipAddressPools:
- production-pool
preferredNodeSelectors:
- weight: 60
preference:
matchLabels:
zone: primaryNote that any soft preference makes the announcing node track label changes. If the labels on your preferred node flap, services will move with them, which is more churn than the pure hash election. Pick stable, slow-changing labels (node role, zone) rather than dynamic state.
Specify network interfaces that LB IP can be announced from
In L2 mode, by default a metallb speaker announces the LoadBalancer IP from all the network interfaces of a node. We can use interfaces in L2Advertisement to select a subset of them.
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- third-pool
interfaces:
- eth0
- eth1This L2Advertisement will make MetalLB announce the Services associated to IPs from third-pool only from the interfaces eth0 and eth1 of all nodes.
The interfaces selector can also be used together with nodeSelectors. In this example, the IPs from fourth-pool will be announced only from eth3 of NodeA:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- fourth-pool
nodeSelectors:
- matchLabels:
kubernetes.io/hostname: NodeA
interfaces:
- eth3The IP from a given IPAddressPool is advertised using the union of all the L2Advertisements referencing it.
This means that the interfaces used to advertise an IP will be the union of the interfaces selected by all the L2Advertisements.
For example:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example-advertisement9
namespace: metallb-system
spec:
interfaces:
- eno1
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example-advertisement10
namespace: metallb-system
spec:
ipAddressPools:
- pool1
nodeSelectors:
- matchLabels:
kubernetes.io/hostname: hostB
interfaces:
- ens18The above YAML indicates that MetalLB should advertise the VIPs of all IPAddressPools including pool1 from the interface eno1 of all nodes, and also advertise the VIPs in pool1 from ens18 of hostB.
In other words, if MetalLB chooses hostB to announce the VIP of pool1, the Speaker should announce the VIP from the interfaces ens18 and eno1; if it chooses other nodes, the Speaker should announce the VIP only from the interface eno1.
The interface selector won’t affect how MetalLB is choosing the leader for a given L2 IP. This means that if it elects a leader where the selected interface is not available, the service won’t be announced. The cluster administrator is responsible to use the combination of interfaces selector and node selector to avoid the problem.
Limiting the advertisement to specific services
By default, an L2Advertisement applies to all services that receive an IP from the
associated pools. You can use serviceSelectors to limit the advertisement to only
services that match specific label selectors.
This is useful when you want different L2 configurations for different services. For example, you might want to announce certain services only from specific interfaces or nodes based on their labels.
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: frontend-services
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
interfaces:
- eth0
serviceSelectors:
- matchLabels:
tier: frontendapiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: backend-services
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
interfaces:
- eth1
serviceSelectors:
- matchLabels:
tier: backendWith this configuration, services labeled tier: frontend that received an IP from first-pool will be announced from
interface eth0, while services labeled tier: backend that received an IP from first-pool will be announced from
interface eth1.
Multiple selectors in the serviceSelectors list are combined with OR logic - a service
matching any of the selectors will be advertised via that advertisement.
serviceSelectors is incompatible with the metallb.io/allow-shared-ip annotation. Services using allow-shared-ip that match an L2Advertisement with serviceSelectors will not be announced, as different services sharing the same IP may match different advertisements and cause split announcements.