Introducing Golang Functions to Kubeless

Andres Martinez
Bitnami Perspectives
4 min readApr 23, 2018

In this story we are going to introduce one of the features included in the version v0.6.0 of Kubeless: Support for Golang functions! It is now possible to deploy your Golang functions using Kubeless in a matter of seconds and you don’t need to handle dependencies installation nor the compilation of your function: Kubeless does that for you! Let’s go over some of the benefits of using this new runtime.

Automatic Build Process

With Kubeless you don’t need to worry about the process of installing dependencies in your local environment. You don’t even need a working Golang environment, the process of compiling and installing the required Go dependencies is handled by Kubeless and takes place in your Kubernetes cluster. Let’s see an example of how this work!

First let’s write our Golang function. This is an inefficient way of calculating if a number is prime:

As you can see, apart from standard libraries we have included two other libraries:

  • github.com/kubeless/kubeless/pkg/functions: Is used to import the types used as parameters for our function
  • github.com/sirupsen/logrus: Is a non-standard log utility that we will use for demonstrating the installation of external dependencies.

For installing dependencies, Kubeless uses dep so in order to specify them we need a Gopkg.toml:

Note that we will ignore the internal Kubeless dependency since it will be already provided by the build system.

Once we have these two files we can deploy our function:

▶ curl -O https://gist.githubusercontent.com/andresmgot/ae02766dacafc13c344429132ffab864/raw/43afe530fb64575ea5c384d518997bf4a1fafbef/func.go
▶ curl -O https://gist.githubusercontent.com/andresmgot/7d0bafb6f61754ab12fe9f24a30fc066/raw/b75635a7263e75acad9606d5986a4bc88d38c01f/Gopkg.toml
▶ kubeless function deploy isprime \
--from-file func.go \
--dependencies Gopkg.toml \
--handler func.IsPrime \
--runtime go1.10
INFO[0000] Deploying function...
INFO[0000] Function isprime submitted for deployment
INFO[0000] Check the deployment status executing 'kubeless function ls isprime'

After some time you will be able to call the function and check its log:

▶ kubeless function call isprime --data '5'
5 is prime
▶ kubeless function call isprime --data '9'
9 is not prime
▶ kubectl logs -l function=isprime
2018/04/20 12:05:45 172.17.0.1:46612 "GET /healthz HTTP/1.1" 200 kube-probe/.
...
time="2018-04-20T13:00:04Z" level=info msg="Checking if 5 is prime"
...

Storing the function as a Docker image

The process of installing and compiling go dependencies and code can be a heavy task that can take several minutes. We want to use our function in production and we want it to scale as fast as possible so we should avoid to compile every time a new pod with our functions is created. To achieve that it is possible to enable the function image builder of Kubeless that generates and stores a Docker image with your function in your favorite Docker registry (I’ll use the DockerHub). To enable it simply create a secret with your registry credentials, activate the feature and restart the controller to reload the changes:

▶ kubectl patch configmap -n kubeless kubeless-config \
-p '{"data":{"enable-build-step":"true"}}'
configmap "kubeless-config" patched
▶ kubectl create secret docker-registry kubeless-registry-credentials \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<YOUR_USERNAME> \
--docker-password=<YOUR_PASSWORD> \
--docker-email=<YOUR_EMAIL>
secret "registry-credentials" created
▶ kubectl delete pod -n kubeless -l kubeless=controller

After executing the above, a Kubernetes Job will be triggered in order to build our function. Once it is finished our function will be using the prebuilt image:

▶ kubectl get job -l function=isprime
NAME DESIRED SUCCESSFUL AGE
build-isprime-1e434ab1e8 1 1 16m
▶ kubectl get pod -l function=isprime -ojsonpath='{ .items[0].spec.containers[0].image }'
index.docker.io/andresmgot/isprime:1e434ab1e879c8eb8160a0047e1fcb2d874f6b1a7788188689e9d8341285ad23

Note: This is also a very useful way of sharing functions. Since the registry is public, you can now deploy the same function executing:

▶ kubeless function deploy isprime --runtime-image index.docker.io/andresmgot/isprime:1e434ab1e879c8eb8160a0047e1fcb2d874f6b1a7788188689e9d8341285ad23

From this point, any new pod will use the cached image and the startup time will be minimal. Apart from that, we can ensure that the exact same code is executed every time. You can find more information about the function builder feature here.

Size and performance comparison

Since Golang functions are just a single binary on top of a minimal Debian image the size of a Golang images are much smaller than interpreted languages like Python or NodeJS. In particular, an example function like the above with dependencies could be around two times bigger for Python, five times bigger for Ruby or ten times bigger for NodeJS.

It is also important that, in specific scenarios, Golang functions perform better than other languages. As an experiment, I’ve created a similar function in Python that uses the same method to obtain if a number is prime. After ten executions, Golang (v1.10) average execution is 0.24 ms while Python (v3.6) is 9.0 ms. This data has been obtained from the Prometheus statistics that the functions expose:

# Golang
function_duration_seconds_sum{method="POST"} 0.002489176
function_duration_seconds_count{method="POST"} 10
# Python
function_duration_seconds_count{method="POST"} 10.0
function_duration_seconds_sum{method="POST"} 0.09038214599786443

Function statistics

Like other runtimes, Golang functions expose Prometheus metrics that reflect, among others metrics, the average execution time or the number of executions/errors per function. Apart from that, there are other tools like InfluxDB that can give you similar statistics like the memory/CPU usage. You can have a visual representation of these metrics using Grafana:

Memory Usage for “isprime” pod

With that I hope I’ve drawn your attention about Kubeless and its latest runtime. You can now start writing your own Golang functions or migrate existing ones! You can reach us in the Kubeless Github repository or in the #kubeless channel in Slack.

--

--