In traditional cloud provider environments, where network load balancers are available, you automatically get a single point of contact to any application running inside the cluster as shown in the picture below.
On prem Kubernetes cluster doesn't have a proper cloud provider configured with a LoadBalancer support like you would have with AWS, GCP, Azure, etc. Therefore, when you create a service with type
LoadBalancer it will sit in the pending state, waiting for an external IP as below.
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP fancyservice LoadBalancer 10.210.1.255 <pending>
To avoid the EXTERNAL-IP pending state of your Kubernetes services you can use MetalLB.
MetalLB aims to redress this imbalance by offering a Network LB implementation , so that Kubernetes services on custom clusters also “just work” as much as possible. In the example below, MetalLB take car to give an IP address to reach the application.
The deployment of MetalLB is quite simple. The current version is v0.9.5 and if you want to use an older version for any reason you can change the version in the URL of the yaml files.
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/namespace.yaml kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/metallb.yaml
And on first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
You should now have spun up a controller pod and one speaker per node.
$ kubectl -n metallb-system get pods NAME READY STATUS RESTARTS AGE controller-5c9894b5cd-trlk5 1/1 Running 0 92d speaker-2wwnk 1/1 Running 0 92d speaker-dt4j2 1/1 Running 0 92d speaker-mrhz9 1/1 Running 0 92d
For the next steps you will need a range of free IP in the subnet of your Kubernetes Hosts. You can find the subnet and IP information of the nodes with
kubectl get nodes -o wide
MetalLB will take control over the IP that you specify in the ConfigMap, in our example it will be a range from 10.210.36.220-10.210.36.229. This command will create the ConfigMap.
cat <<EOF | kubectl create -f - apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: - 10.210.1.220-10.210.1.230 EOF
Let's test it with a simple NGINX helm deployment
kubectl create ns nginxdemo helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update helm install nginxdemo bitnami/nginx --set service.type=LoadBalancer --namespace nginxdemo
You will see that the service received an external IP from MetalLB
$ kubectl -n nginxdemo get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginxdemo LoadBalancer 10.252.57.89 10.210.36.223 80:31505/TCP 24s
And if your network allows it, you can now access the service using the external IP and the service port
If you want to clean the demo environment
helm uninstall nginxdemo && kubectl delete ns nginxdemo
Feel free to comment this article if you have questions.