A lot of solutions rely on the fact that Kubernetes has LoadBalancer type services. And why not, it's a fantastic way to indirectly get a load balancing solution in place in front of the applications. And of course, there are other nice building blocks that rely on existence of these load balancers such as external-dns and others. Unfortunately, not all environments are such that there is something to be configured as a load balancer for a service. The environment could be on-premise and/or have network setup in a way that MetalLB cannot be setup. Or you might be running just a small test setup locally and do not wish to build any heavy solutions for it.

To help with these kind of cases we're happy to unveil our newest open source component to the land of Kubernetes. Say hello to Akrobateo, a universal load balancer service implementation. Akrobateo can work in any environment which makes it suitable for many use cases. And it's super light-weight too. It is implemented as an operator that reacts when it sees type: LoadBalancer services in the cluster.

Akrobateo draws heavy inspiration from K3S servicelb controller: https://github.com/rancher/k3s/blob/master/pkg/servicelb/controller.go. As K3S controller is fully and tightly integrated into K3S, with good reasons, we thought we'd separate the concept into generic operator usable in any Kubernetes cluster.

To deploy Akrobateo, just use the pre-made deployment manifests to deploy the operator. It'll setup the operator itself and all the needed RBAC rules for it to operate properly.

Let's dig in how Akrobateo works by setting up an example service. As a typical case, you have a Deployment for which you need to create a load balancer in front. For our example deployment we'll use a typical echoserver based example:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: echoserver
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: echoserver
    spec:
      containers:
      - image: gcr.io/google_containers/echoserver:1.0
        imagePullPolicy: Always
        name: echoserver
        ports:
        - containerPort: 8080

Then to create the needed Service in front of it we'll use a simple LoadBalancer type service:

apiVersion: v1
kind: Service
metadata:
  name: echoserver
spec:
  type: LoadBalancer
  ports:
  - name: echo
    port: 8080
    targetPort: 8080
    protocol: TCP
  selector:
    app: echoserver

There's nothing atypical in this, make sure you use proper selector labels to match the pods in the service and also remember to configure the service port(s) properly to match what the application is listening on.

Once Akrobateo sees a service like this it'll start its operations.

Step one of Akrobateo in action is an automatic creation of a DaemonSet to deploy an actual load balancer for the service on each node. The pods in the DaemonSet will do the actual load balancing using the trusted workhorse of the entire internet, iptables. The neat "trick" here is that even as the service is of type LoadBalancer it will still get the cluster IP assigned for service. So the actual balancer pod will "route" the traffic from a host port to the services cluster IP on a specific port. Simple eh? :)

The second part of Akrobateo in action is the fact that once the balancer pods become active, Akrobateo will sync the node's addresses as the external addresses in the service details. So you should see something like this:

$ kubectl get svc
NAME               TYPE           CLUSTER-IP       EXTERNAL-IP                                                             PORT(S)                         AGE
echoserver         LoadBalancer   172.32.196.236   147.75.100.201,147.75.101.127,147.75.102.57,147.75.85.43,147.75.85.45   8080:31278/TCP   34m
kubernetes         ClusterIP      172.32.0.1       <none>                                                                  443/TCP                         5d3h

Naturally, hitting any of the reported LB addresses on the configured port should get you directed into the application:

$ curl 147.75.85.43:8080
CLIENT VALUES:
client_address=('172.31.5.104', 58861) (172.31.5.104)
command=GET
path=/
real path=/
query=
request_version=HTTP/1.1

SERVER VALUES:
server_version=BaseHTTP/0.6
sys_version=Python/3.5.0
protocol_version=HTTP/1.0

HEADERS RECEIVED:
Accept=*/*
Host=147.75.85.43:9090
User-Agent=curl/7.57.0

The third part of Akrobateo in action is when you actually go and delete the given service. Akrobateo will automatically react and remove the created daemonset. No traces are left behind. :)

Please give Akrobateo a test run if you have a suitable use case in your hands. Remember that this is the first public release so there might be still some rough edges. And as always, we'd be delighted to hear what you think of it and if you've hit into any troubles. So create issues, give stars and open PR's on the GitHub repo.

About Kontena Inc.

Kontena Inc. is specialized in creating the most developer friendly solutions for running containers. Kontena's products are built on open source technology developed and maintained by Kontena. Kontena was founded in 2015 and has offices in Helsinki, Finland and New York, USA. More information: www.kontena.io.