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 quickly 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 Kubernetes configuration.

Yes, of course I could set up some CI system, but sometimes that’s a bit too much for a local dev environment.

The serverless paradigm goes in 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.

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 workstation
  • a two-node k3s cluster running on Ubuntu

If your setup is very different, please check the Kubeless website (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 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 was installed properly with:

$ kubeless version

Let’s continue by deploying some functionality.

Deploying a Function

Now we are going to deploy those “small bits of code” mentioned earlier— the so-called “functions”.

Create the code in a file called echo.py:

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

Then deploy it to the cluster with:

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

That’s all!

Do a quick check that the function was 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: the STATUS should be READY.

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

Test

Finally, test the function by calling it via kubeless:

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

Success!

Cleanup

If you want to remove everything again, here are the commands to clean up what was 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 the additional CLI. A Kubeless function is, in Kubernetes terms, a custom resource (CRD). Therefore, Kubeless functions become Kubernetes objects and we can use kubectl as usual.

Let’s try it out.

First, delete the previous function if you haven’t already (see “Cleanup” ).

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:

$ kubectl apply -f echo.yaml

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, forward the port of the cluster node to your local machine:

$ kubectl port-forward service/echo 8080:8080

Then, in another terminal, curl into the cluster to call the 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 is the output. If not, continue with the next section.

Troubleshooting

It ‘s likely something won’t work as expected the first time through this tutorial. I ran into a problem after deploying my first function: the service was not reachable and I couldn’t call the function.

When checking your function, the status might be “NOT READY” instead of “READY”, and the associated pod might be stuck in “CrashLoopBackOff”.

The usual approach is to check the logs of the Kubernetes pod.

First get the pod name:

$ 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 was I able to find out that I had chosen a Python version that was no longer available; I had to switch to a higher version (>= 3.x). I also had to change my code syntax because this is valid in Python 2:

print "Hello World!"

but in Python 3 it must be:

print("Hello World!")

Just for the giggles.

Conclusion

Hopefully your first trip into serverless was successful. I enjoyed it and see many possibilities to streamline my development workflow.

Now explore more 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