Live Workshop: How to Measure ROI of Developer Experience
Register now!

Serverless Development with Kubeless and Okteto

I'm a huge fan of serverless programming. I just love the simplicity of writing a small piece of code, running a command, and have it available on demand. Last year I spoke at Kubecon's Serverless Practitioners Summit about my experience around building functions with OpenFaaS, and how you can leverage Okteto to make it even easier (a version of that talk is also available as a guest post in the OpenFaaS' blog, if you prefer that format).

I had a lot of great conversations after that talk. In one of those, someone asked me if okteto could also work the same way with Kubeless. I wasn't familiar with Kubeless at the time, but I remember saying that as long as Kubeless "spoke Kubernetes", it should work. Someone reminded me of that conversation the other day, so I decided to try it out. And, spoiler alert, it does!

In this post, we'll talk about how to install Kubeless in your cluster, we'll deploy our first function, and then we'll use okteto to quickly iterate on a a second version of the function directly in our Kubernetes cluster.

What's Kubeless?

From their website:

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!

Kubeless is pretty cool. One of the biggest benefits, in my opinion, is that function deployment is super simple (specially when comparing it with AWS Lambda and others). You write your code, you put it in a zip file (for the case where there's more than one file), and you run one command. You follow a very specific contract, and you don't have to worry about Dockerfiles, deployment manifests, or even webservers!

The other cool thing is that Kubeless functions are deployments. This allows us to take advantage of the rest of Kubernetes when building our applications. For example, you can still use something like helm to deploy a standard MongoDB database, and use kubeless to deploy a function that consumes it. Or to develop with okteto 😉.

Prerequisites

For this post you'll need:

  • A Kubernetes cluster (kind or minikube will work in a pinch).
  • Cluster admin access to your cluster (Kubeless installs CRDs and creates ClusterRoles).
  • kubectl installed and configured to talk to your cluster.

Install Kubeless in your Kubernetes cluster

First, you need to install kubeless. Full instructions are available here.

kubeless contains two pieces: a controller that's running on your Kubernetes cluster, and a CLI that runs on your development machine.

Run the commands below to install Kubeless in your cluster:

$ 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
clusterrole.rbac.authorization.k8s.io/kubeless-controller-deployer created
clusterrolebinding.rbac.authorization.k8s.io/kubeless-controller-deployer created
customresourcedefinition.apiextensions.k8s.io/functions.kubeless.io created
customresourcedefinition.apiextensions.k8s.io/httptriggers.kubeless.io created
customresourcedefinition.apiextensions.k8s.io/cronjobtriggers.kubeless.io created
configmap/kubeless-config created
deployment.apps/kubeless-controller-manager created
serviceaccount/controller-acct created

This will install Kubeless' CRDs as well as create a deployment with the controller. You can check the status of the deployment by running the command below:

$ kubectl get pod -n=kubeless
NAME                                           READY   STATUS    RESTARTS   AGE
kubeless-controller-manager-7ccdccb78b-hn7mf   3/3     Running   0          1m

Install the kubeless CLI:

MacOS / Linux
$ export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kubeless/releases/latest | grep tag_name | cut -d '"' -f 4)
$ 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/

Windows
  1. Download the latest release from the releases page.
  2. Extract the content and add the kubeless binary to the system PATH.

Deploy your first Kubeless function

We are now ready to create a function. We'll keep it simple and create a function that says hello and echos back the data it receives.

Open your favorite IDE, create a file named hello.py and paste the code below:

def hello(event, context):
  print(event)
  return 'Hello, you said: %s' % event['data']

Functions in Kubeless have the same format regardless of the language of the function or the event source. In general, every function:

  1. Receives an object event as their first parameter. This parameter includes all the information regarding the event source. In particular, the key 'data' should contain the body of the function request.
  2. Receives a second object context with general information about the function.
  3. Returns a string/object that will be used as response for the caller.

More information on Kubeless functions is available here.

Create the function with the kubeless CLI:

$ kubeless function deploy hello --runtime python3.4 --from-file hello.py --handler hello.hello
INFO[0000] Deploying function...
INFO[0000] Function hello submitted for deployment
INFO[0000] Check the deployment status executing 'kubeless function ls hello'

Let's take a closer look at the command:

  1. hello: This is the name of the function we want to deploy.
  2. --runtime python3.4: This is the runtime we want to use to run our function. Run kubeless get-server-config to see all the available options.
  3. --from-file hello.py: This is the file containing the function code. This can be a file or a zip file of up to 1MB of size.
  4. --handler function.hello: This specifies the file and the exposed function that will be used when receiving requests.

Your function will be ready in a minute or so. Check its state by running the command below:

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

Once the function is ready, you can call it by running:

$ kubeless function call hello --data 'Hey'
Hello, you said: Hey

Develop your Function Directly in Kubernetes with Okteto.

If you look into your cluster after deploying your function, you'll notice that the kubeless controller created a deployment to run your function code. This means that you can use okteto to develop it directly in the cluster!

$ kubectl get deployment --show-labels
NAME   READY   UP-TO-DATE   AVAILABLE   AGE     LABELS
hello  0/1     1            0           85s     created-by=kubeless,function=hello

okteto provides a local development experience for Kubernetes applications. You write code locally in your favorite IDE and Okteto synchronizes it automatically to your cluster. The Okteto CLI is open source, and the code is on GitHub. It is a client-side only tool that works in any Kubernetes cluster.

Follow the instructions below to install okteto:

MacOS / Linux
$ curl https://get.okteto.com -sSfL | sh
Windows
  1. Download https://downloads.okteto.com/cli/okteto.exe
  2. Add the okteto binary to your system's $PATH.

The first thing we need to do is generate the okteto manifest. The manifest tells okteto which deployment you are going to be working on and where to synchronize your code. Go back to your favorite IDE, create a file named okteto.yml, and paste the content below:

name: hello
command: bash
workdir: /
syncs:
  - .:/kubeless

Let's take a deeper look the content of the manifest:

  1. name: This is the name of the function you want to develop in.
  2. command: This is the command you want to execute. We use bash to get a remote terminal into our development container.
  3. workdir: This is the working directory of our remote terminal. We use / because that's where we are going to be executing our code from.
  4. syncs: Our local files are synchronized to /kubeless

You are now ready to start developing directly in your cluster. Buckle pu, go back to your terminal and run the command below:

$ okteto up
 ✓  Development container activated
 ✓  Files synchronized
    Namespace: okteto
    Name:      hello

I have no name!@hello-8497c7694f-lgd98:/$

The command will "drop us" in a terminal inside our remote development container. This is the same container that kubeless uses for your function, except that now okteto is keeping your file system automatically synchronized.

Run the command below to start your function. This is the same command that kubeless runs to start the function:

$ python3.4 kubeless.py
Bottle v0.12.13 server starting up (using CherryPyServer())...
Listening on http://0.0.0.0:8080/
Hit Ctrl-C to quit.

At this point, your function is up and running, just as if you deployed it with kubeless. Open a second local terminal, and call it using the kubeless CLI:

$ kubeless function call hello --data 'Hey'
Hello, you said: Hey

Let's iterate on our function. Open hello.py in your favorite IDE, change the response message and save the file:

def hello(event, context):
  print event
  return 'Hello from Okteto, you said: %s' % event['data']

Go back to the remote terminal, press CTRL+C to stop your function, and then start it again.

$ python3.4 kubeless.py
Bottle v0.12.13 server starting up (using CherryPyServer())...
Listening on http://0.0.0.0:8080/
Hit Ctrl-C to quit.

Call your function again from the second terminal:

$ kubeless function call hello --data 'Hey'
Hello Kubernetes, you said: Hey

Look at that response carefully. Notice something different? Your code changes were applied instantly, without you having to redeploy your function. Pretty cool no?

How does it work?

When you run python3.4 kubeless.py, the kubeless script dynamically loads the contents of the /kubeless folder, and then uses it to execute your function when it gets a request. This is how Kubeless works. Behind the scenes, okteto is keeping your local folder synchronized with the /kubeless folder. Every time you create, save, or delete a file, the change is automatically replicated in your function's container.

okteto's file synchronization allows you to quickly iterate in your changes, without having to redeploy your function every time. More information on this is available here.

Cleanup

You can delete the function using the command below:

$ kubeless function delete hello
$ kubeless function ls
NAME        NAMESPACE   HANDLER     RUNTIME     DEPENDENCIES    STATUS

And to delete kubeless:

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

Conclusion

In this tutorial we talked about Kubeless, how to set it up and how to deploy our first function. Then we talked about how you can use okteto together with kubeless to speed up your development cycle. We chose a simplistic function so we can focus on the development flow, but the same approach works for more complex scenarios.

Traditionally, you'd have to write your code locally, package it and deploy it to Kubernetes in order to test your changes. With okteto, you run okteto up once, and iterate directly in your function's container. Not only do you save minutes on each validation loop, but since you are running your code directly in your container, you are also testing that your code works as a kubeless function from the very beginning.

okteto works with any Cloud Native Application. Check out our samples repository and learn how to use it to build applications with your favorite framework and programming language.

What do you think about serverless programming? Do you ❤️? Do you 😭 the minute you think about it? Reach out to us on Twitter and lets us know.

Ramiro BerrellezaCEO & Co-founder View all posts

Automate Provisioning Any Dev Resource on Any Cloud Provider With Pulumi and Okteto

The Value It is common in today's landscape to build microservices-based applications that leverage resources like RDS databases, storage buckets, etc...

October 19, 2023
Avatar of Arsh SharmaAvatar of Arsh SharmaArsh Sharma

How Developers Can Seamlessly Collaborate When Building Microservice Apps

Building microservices based applications is inherently challenging. Given the multitude of components involved, it is unrealistic to expect any individual...

October 10, 2023
Avatar of Arsh SharmaAvatar of Arsh SharmaArsh Sharma