BareMetal LoadBalancer for Kubernetes using MetalLB
In this post we’ll install and use the MetalLB L2 load balancer for Kubernetes.
The problem MetalLB solves is a familiar one: if you’re not on AWS, GKE or AKS, a LoadBalancer service on Kubernetes simply stays stuck in the pending state. MetalLB steps in to create a load balancer for your bare-metal Kubernetes, supporting both Border Gateway Protocol and L2.
To have something to work with, I created a DigitalOcean droplet in Frankfurt with 2 GB of RAM and installed kubeadm on it.
The MetalLB installation YAML takes care of the groundwork for us: it first creates a namespace for MetalLB, then creates and applies RBAC for that namespace.
Once the YAML is applied, it’s worth checking that our pods and services are running without any errors.
root@frankfurt-kubeadm1-ub2g:~/metallb# kubectl get po -n metallb-system
NAME READY STATUS RESTARTS AGE
controller-765899887-jn8jq 1/1 Running 0 23s
speaker-z6p4q 1/1 Running 0 24s
These two pieces split the work between them: the speaker sends ARP requests and obtains IP addresses for the load balancer, while the controller allocates an IP address to the LoadBalancer service for Kubernetes.
The last step is to hand MetalLB a config, where we define which protocol and which IP addresses will be used for the service.
Since I’m building this example on kubeadm with just one node, I want to publish to that node’s own IP address.
That means giving MetalLB a single host CIDR, “/32”.
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 159.89.3**.***/32
With the config applied, we can dig into the speaker logs to see it in action.
{"caller":"arp.go:102","interface":"weave","ip":"159.89.3**.***","msg":"got ARP request for service IP, sending response","responseMAC":"b2:1e:26:**:**:**","senderIP":"159.89.3**.***","senderMAC":"c6:a4:2a:**:**:**","ts":"2018-10-13T12:04:58.497978319Z"}
Our kubectl get svc looks awesome:
root@frankfurt-kubeadm1-ub2g:~/metallb# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.109.176.39 159.89.3**.*** 80:30311/TCP 8m36s
Service panel:
Trying it out:
root@frankfurt-kubeadm1-ub2g:~/metallb# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.109.176.39 159.89.3**.*** 80:30311/TCP 17m
root@frankfurt-kubeadm1-ub2g:~/metallb# curl 159.89.3**.***
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
