Exploring Serverless Computing with Kubeless
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.
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..