Skip to main content

Exploring Serverless Computing with Kubeless

·5 mins

First Steps with Kubeless on k3s #

It is time to go serverless, at least for me. As a developer I want to write application code and get it running “somewhere” as quick as possible.

I don’t want to switch hats during development just to get my code into some cloud by creating new Docker images and changing some Kubernetes configuration.

Yes, of course, I could setup some CI system, but sometimes this is a bit too much in a local dev-environment.

The serverless paradigm goes into the right direction in my opinion. Time to get a feel for it.

I have chosen Kubeless as a framework because I want to play on my local k3s-cluster with it.

https://levelup.gitconnected.com/setup-your-own-kubernetes-cluster-with-k3s-take-2-k3sup-a5d9453f709f

From their website, they describe it as follows

Kubeless is a Kubernetes-native serverless framework that lets you deploy small bits of code (functions) without having to worry about the underlying infrastructure. It is designed to be deployed on top of a Kubernetes cluster and take advantage of all the great Kubernetes primitives. If you are looking for an open source serverless solution that clones what you can find on AWS Lambda, Azure Functions, and Google Cloud Functions, Kubeless is for you!

Therefore, this post is a tutorial about the Kubeless framework to start exploring what it means to deploy serverless functions.

Enough said, let’s dive right in.

One second, before we start I have to mention that my setup is

  • a MacBook Pro as local work station
  • a two-node k3s cluster running on Ubuntu

In case your setup is very different, please check the Kubeless website, see links at the end of this post.

Installation #

First, we install everything with the following commands:

$ export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kubeless/releases/latest | grep tag_name | cut -d '"' -f 4)
$ kubectl create ns kubeless
$ kubectl create -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml

As with every good tool, Kubeless also comes with its own CLI to make things a little bit easier.

$ export OS=$(uname -s| tr '[:upper:]' '[:lower:]')
$ curl -OL https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless_$OS-amd64.zip && unzip kubeless_$OS-amd64.zip && sudo mv bundles/kubeless_$OS-amd64/kubeless /usr/local/bin/

Check if it has been installed properly with:

$ kubeless version

Let’s continue deploying some functionality.

Deploying a Function #

Now we are going to deploy those “small bits of code” that I have mentioned in the beginning, the so called “functions”.

Let’s create the code by writing the following into a file called echo.py.

def echo(event, context):
  print(event)
  return event['data']

Then everything gets onto the cluster with:

$ kubeless function deploy echo --runtime python3.8 --from-file echo.py --handler echo.echo

That’s all!

Do a quick test if the function has been created properly:

$ kubeless function ls echo
NAME NAMESPACE 	HANDLER  	RUNTIME  	DEPENDENCIES 	STATUS
echo	 default  	  echo.echo	python3.8	            	  1/1 READY

Especially check the last column that the STATUS is actually READY.

If it is not working, please check the section called “Troubleshooting”.

Test #

Finally, it is time to test the function by calling it via kubeless:

$ kubeless function call echo --data 'Hello World!'
Hello World!

Success!

Cleanup #

In case you want to get rid of everything again, here are three commands to cleanup what has just been installed.

$ kubeless function delete echo
$ kubectl delete -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml
$ kubectl delete ns kubeless

Using Kubeless without kubeless #

What a weird title, but it makes sense after reading this section.

We are still on Kubernetes and everything works without any additional CLI like kubeless.

A Kubeless function is in Kubernetes nothing more than a “custom resource definition” (CRD). Therefore, Kubeless functions turn into Kubernetes objects and we can use kubectl as we are used to.

Let’s try it out.

Now, let’s delete the previous function. If not already done so, see the “Cleanup” section.

Put the following into a file called echo.yaml.

---
apiVersion: kubeless.io/v1beta1
kind: Function
metadata:
  name: echo
spec:
  deployment:
    metadata:
      annotations:
        "annotation-to-deploy": "value"
    spec:
      replicas: 2
      template:
        metadata:
          annotations:
            "annotation-to-pod": "value"
  deps: ""
  function: |
    def echo(event, context):
      print(event)
      return event['data']
  function-content-type: text
  handler: echo.echo
  runtime: python3.8
  service:
    selector:
      function: echo
    ports:
    - name: http-function-port
      port: 8080
      protocol: TCP
      targetPort: 8080
      nodePort: 30333
    type: NodePort

Then, install it onto the cluster as usual:

$ kubectl apply -f echo.yml

Check if it has been deployed:

$ kubectl get svc echo
NAME   TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
echo   ClusterIP   WW.XX.YYY.Z   <none>        8080/TCP   16m

All fine!

Now, to test the service, we need to forward the port of the cluster node to our local machine.

$ kubectl port-forward service/echo 8080:8080

Then, in another terminal, we curl into the cluster to call our function.

$ curl -L --data '{"echo":"Hello World!"}' --header "Content-Type:application/json" localhost:8080/api/v1/namespaces/default/services/echo:http-function-part/proxy/

Et voilà, there we have our output. Hopefully … If not, continue with the next section.

Troubleshooting #

It is likely that something is not working as expected when running through the tutorial the first time. I ran into a problem after deploying my first function. The service was not reachable and I was not able to call the function. I had no clue why it was not working.

When checking your function, that status might be “NOT READY” without changing to “READY” and the status of the associated pod might be in status “CrashLoopBackOff” indefinitely.

The usual “strategy” was by checking the logs of the Kubernetes pod.

Call this to get the name of the pod.

$ kubectl get pods
NAME      READY   STATUS        RESTARTS   AGE
echo-xzy  1/1     Running       0          4m35s

Then, get the logs.

$ kubectl logs echo-xzy

Only then I was able to find out, that I wanted to use a version of Python that was not available any more and I had to switch to a higher version (>= 3.x) to make it work. Also had to change the syntax of my code in order to make it work again, because in Python 2 this is valid code

print "Hello World!"

But in Python 3.x the syntax needs to be

print("Hello World!")

Just for the giggles.

Conclusion #

Hopefully, your first trip into Serverless was successful. I have really enjoyed it and I see many possibilities opening up in the future to change and especially streamline my development workflow.

Now it is time to explore more of the already existing functions and write some on your own. I have put some links below to keep you going.

Feel free to buy me a coffee if you liked this post..

Resources #