In this article I will show how to self host Azure functions in a Kubernetes cluster.
In a previous article about scaling Azure functions I showed how to optimize scaling of queue based functions. The architecture described in the article resulted in a fairly scalable system with high throughput. However, there was one downside to the design. As I pointed out in the article, Azure functions will eventually scale up, but the ramp up time to get many Azure functions to run in parallel is from my experience relatively high. In a system with variable traffic loads, this could be a problem since it leads to very unpredictable performance once the system spins down.
The performance tax you pay when waking up functions is usually referred to as a cold start. Cold starts are mainly a problem with truly serverless functions running in the consumption tier since the extra functions quickly spin down.
I don’t really see a perfect solution for avoiding cold starts in the consumption tier, so a hybrid solution is probably the best route to take. In a pure Azure solution you could combine the consumption tier with one of the other tiers (e.g. Basic and Premium). This enables you to leave a few functions always on, but this comes at a cost since you have to pay a fixed fee for the statically allocated Azure resources. In this post I will describe an alternative, but similar approach that enables you to run Azure functions in a self hosted Kubernetes cluster. Of course, running functions in Kubernetes pods also comes at a cost, but it’s at least an interesting alternative to consider.
In my example I will be using a simple ServerBus triggered function. The source can be found below:
The first step is to Dockerize the Azure function. Luckily this can be done using the Azure function core tools. Just run the command func init --docker-only to scaffold a generic Dockerfile for your Docker image.
Below is a sample Dockerfile generated by the tool:
The generated Dockerfile can then be used to generate a Docker image for your Kubernetes cluster.
The next step is to create a Kubernetes yaml file that will create pods for the Azure function in your Kubernetes cluster.
My sample file is included below
In my case I am telling Kubernetes to create 10 replicas of the function. The idea here is that this will create a baseline of resources that I can combine with pure consumption tier functions running in Azure. This will prevent my system from starting from zero functions after a period of inactivity. Running in Kubernetes also gives me more control over cpu and memory allocations for the function pods. Another benefit is that this enables you to run Azure functions on any cloud provider infrastructure.