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 http://10.210.36.223:80
Et voilà!!
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.
References: