Cloud Native Serverless Functions with Ballerina
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 thecontext
with the information about the function environment. We’ll receive the text to tweet using the parameterevent.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.