Cloud Native Serverless Functions with Ballerina

Ballerina and Kubeless logos

In this post we are going to show how you can deploy and manage serverless functions with Ballerina. Among other things, you will see how simple is to create scalable microservices using Ballerina and the possibilities it opens thanks to Kubeless: our native serverless framework for Kubernetes. We will also explain how you can share Ballerina functions and how you can add support for new runtimes to Kubeless.

If you’d like to learn more, join us during the “Ballerina Serverless with Kubeless” webinar on July 11th at 9:00 am PST. Register Now.

What is Ballerina

Ballerina is a brand new language that targets Cloud Native infrastructures and “makes it easy to write microservices that integrate APIs”. As we’ll see in this blogpost, we are going to generate an interesting microservice that integrates with other services (in this case Twitter) with just a few lines of code.

Ballerina is a compiled (and typed) language, so you get all the benefits that these languages provide. It has a lot of ready to use “packages” as part of Ballerina Central. These packages are really helpful when integrating your code with external services like Twitter, Gmail or Github.

Deploying a Ballerina function

Let’s start with a simple function that sends a tweet whenever it receives a request:

If we take a look to this function, we notice several things:

  • It has several import clauses that are used for two things: to identify the required dependencies when compiling the function, and to load them at run time. This means that it’s not necessary to create a different file for specifying dependencies.
  • It has an endpoint that lets us initialize the twitter instance. This will read the credentials from a configuration file. We will get back to that in a moment.
  • And finally, it has the function definition. As any Kubeless function, it receives two parameters: an event with the data of the request, and the context with the information about the function environment. We’ll receive the text to tweet using the parameter event.data.

Note that the Twitter credentials needed to publish the tweet are read from a configuration file. This is a very simple (toml) file in which we are going to store some key/values with the credentials that can be retrieved from https://apps.twitter.com using any twitter account.

Once we have the function and the configuration we can deploy the Kubeless function:

# Download the function file
curl -O https://gist.githubusercontent.com/andresmgot/c3297fcc3b7df786ab4b3d3a96de1da3/raw/0b9c0f83b410893731bbac80ebcc3db686702ee8/twitter.bal
# Download the config file
curl -O https://gist.githubusercontent.com/andresmgot/5e239531307791dd5b54569547c5f19a/raw/eed4fe224663721081d1f55d607f2b7e083132d3/kubeless.toml
# Now it is needed to edit the configuration with the credentials
# Bundle the two files in a Zip
zip func.zip twitter.bal kubeless.toml
# Deploy the function
kubeless function deploy ballerina-tweet \
--runtime ballerina0.975.0 \
--from-file func.zip \
--handler twitter.sendTweet

After a short time, we can see that the function is deployed and we can submit our tweet!

$ kubeless function ls ballerina-tweet
NAME NAMESPACE HANDLER STATUS
ballerina-tweet default twitter.sendTweet 1/1 READY
$ kubeless function call ballerina-tweet \
--data 'Hello from Kubeless and Ballerina!'
Tweet ID:1010148848528961536

Store functions as Docker Images

In my previous post I explained why it is important to enable the function builder feature for compiled languages in Kubeless. In a nutshell what you get is:

  • Faster redeploys: The function is compiled only once. Further redeploys will just reuse the existing docker image which is much faster.
  • Immutable deployments: Every time a function is deployed it will use the exact same image. Without this, it would install and resolve dependencies every time it is deployed.
  • Shareable functions: The functions can be shared (as docker images) to other users who have access to the same Docker registry.

The main issue if we store our previous function as a Docker image is that anyone who pulls it will have our credentials. To avoid this, we are going to use a slightly different version of the function in which the credentials are retrieved from environment variables instead of a config file. The only difference is that we are not going to include the `kubeless.toml` file. Ballerina will automatically fallback to use environment variables to try to retrieve the required info. After that we can either set the credentials as regular environment variables, or use a Kubernetes Secret to make it more secure. We have already build and pushed our function with Kubeless so you can deploy the same function just executing:

$ kubeless function deploy ballerina-tweet-env \
--runtime-image andresmgot/ballerina-tweet-env:de79fa463504c47cb6effea4582402d0d2aa07ec94fc0a4023c5e671f2d94106 \
--env consumerKey=CONSUMER_KEY \
--env consumerSecret=CONSUMER_SECRET \
--env accessToken=ACCESS_TOKEN \
--env accessTokenSecret=ACCESS_TOKEN_SECRET

Adding new runtime languages to Kubeless

Adding Ballerina to the Kubeless ecosystem was possible by following the simple instructions that you can find in this guide. Currently, in addition to Ballerina, Kubeless supports NodeJS, Python, Ruby, Golang, .NET and PHP functions. If you are interested in having serverless functions in a different language, or want to add a new feature to an existing language, you can find us in the Kubeless Github repository. Your contribution will be more than welcome!

If you’d like to learn more, join us during the “Ballerina Serverless with Kubeless” webinar on July 11th at 9:00 am PST. Register Now.