Running metallb in Layer 2 mode
MetalLB is a load-balancer implementation for
bare metal Kubernetes clusters. I’ve used it succesfully to add support for
LoadBalancer type service on bare-metal kubernetes clusters to expose my
services outside the cluster.
First check if metallb is compatible with your CNI plugin at https://metallb.universe.tf/installation/network-addons/.
metallb is as simple as running the following command.
kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.8.3/manifests/metallb.yaml.
This deploys two components - controller and speaker. controller is deployed as a Kubernetes Deployment and speaker is deployed as a Kubernetes Daemonset. Metallb deals with two primary tasks - Address allocation and external anouncement.
Once metallb is installed, you configure it by creating a
under the same namespace it is installed in(metallb-system). Metallb works in
two modes - Layer2 and BGP. I’ve used it in Layer2 as it is simplest to configure.
Following is example of configuration for Layer2 mode configuration:
apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: # Change this address pool to your IP range - 192.168.1.240-192.168.1.250
How does it work?
controller component of metallb watches for creation or updation of
kubernetes Service objects of type
LoadBalancer and assigns an IP from the
address pool given to it from the configuration.
The job of
speaker component is to announce this address.
speaker is deployed as a
Daemonset and so runs on every node. When
controller assigns an IP to a
speaker, it announces this event by sending out gratuitous ARP messages and by
replying to ARP requests.
If a node that owns the IP goes down, another node takes over the IP and starts responding to the ARP requests.
One disadvantage with Layer 2 mode is that a single node attracts all the service IP’s traffic. From there, kube-proxy spreads the traffic across the service’s pods. So there is failover between nodes but there is no node level loadbalancing. So the service’s ingress bandwidth is limited to the bandwidth of single node.
What virtual IPs should I use?
In Layer 2 mode, the virtual IPs that you give to metallb should be routable to the cluster network. This means all the nodes IPs and the extra virtual IPs should be in same subnet.
How many virtual IPs do I need?
If you are running inside a private network, it should be easy to get as
many IP addresses as you want. At minimum you would need as many IPs as the
LoadBalancer services you have so that each service get’s it’s own IP.
Sharing IPs among different services
If for some reason, you do not have the luxury of getting the reuired number of
IPs or if you want to expose all the services on same IP, metallb supports IP
sharing mode where multiple services can use same IP given that they use
different service ports. To enable IP sharing, you need add an annotation with
metallb.universe.tf/allow-shared-ip and use same value for this annotation
in all the services you want to collocate on same IP. To guarantee that IP is
shared among the services, you also need to set the
to required IP. If only annotation is set and
spec.loadBalancerIP is not set,
metallb tried to collacate the services on same IP but it is not guranteed.
apiVersion: v1 kind: Service metadata: name: gateway labels: app: gateway annotations: # Use `my-shared-ip` value in other services which # should be collocated with this service metallb.universe.tf/allow-shared-ip: my-shared-ip spec: type: LoadBalancer # Set loadBalancerIP to guarantee services share the IP loadBalancerIP: 192.168.1.240 selector: app: gateway - name: http port: 80 targetPort: 80