/ Howto

Introduction to the fn project

The Fn project is an open-source container-native serverless platform that you can run anywhere -- any cloud or on-premise. It's easy to use, supports every programming language, and is extensible and performant.

These are the lines you are greeted with if you go to the fn projects website. So what does all this mean? Well, it basically means that another *AAS product has reached us, this time its FAAS, or Function as a service. This concept is not new, and several of the big *AAS providers have their own implementations running. AWS has it's Lambda, Google has Google Cloud Functions and Azure has Azure Functions. The fn project will be the serverless solution Oracle will offer to it's cloud customers, with some modifications based on it's own cloud infrastructure.

The common ground between these platforms are based on the serverless manifesto

  • Function are the unit of deployment and scaling.
  • No machines, VMs, or containers visible in the programming model.
  • Permanent storage lives elsewhere.
  • Scales per request; Users cannot over- or under-provision capacity.
  • Never pay for idle (no cold servers/containers or their costs).
  • Implicitly fault-tolerant because functions can run anywhere.
  • BYOC - Bring Your Own Code.
  • Metrics and logging are a universal right.

So what does the Fn project bring to the mix?

  • First of all it is open source (sponsored by Oracle) which gives you all the open source goodies.
  • It's cloud agnostic - no need to run at a specific cloud provider, or even in the cloud at all
  • Docker based
  • Very easy to get started (as you will see)

Getting started

The first thing you need to get going is docker (version 17.10.0-ce or later). I run Windows on my laptop, but fired up an Ubuntu 16 VirtualBox image to run it. There is a quick guide on how to install docker on Ubuntu on the docker webpage which I used, and got it quickly up and running. To ensure that docker is correctly installed and that the daemon is running, run the following

sudo docker run hello-world

and you should see something like this

Docker hello world output

Quick tip
If you don't want to use sudo every time you run the docker commands, add your personal user to the docker group. I ran the below command, and afterwards I could run docker as my regular user.

sudo usermod -aG docker functiontester
docker run hello-world

The next step is to get the CLI tool. This is strictly speaking not necessary, but it will make your life easier when we go forward. To use the automatic installer, run the following to download it

sudo curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

And that is actually all you need...

So now that you have all the needed components, it's time to fire up the stack

fn start

This will download the needed docker images (if not available on your machine) and give you an output similar to this

Output from fn start

As you might see in the highlighted text, it has now fired up an image that listens to port :8080 locally. If you already have something running on that port you will get conflicts. The container can also be checked with standard docker commands.

functiontester@ubuntu:/media/sf_function/hello$ docker ps
CONTAINER ID        IMAGE                COMMAND             CREATED             STATUS              PORTS                              NAMES
4c3484b3e59b        fnproject/fnserver   "./fnserver"        57 seconds ago      Up 55 seconds       2375/tcp, 0.0.0.0:8080->8080/tcp   fnserver

And if you go to the port in a webbrowser, you will see something like this if all is OK.

Web output from fn

So now you are running your very own serverless platform!

Your first function (Java)

So your up and running, but it doesn't do much yet. So we need some code to run on our new platform. Again we will use the CLI tool we installed earlier, as this has commands for creating skeleton projects for different runtimes. So, for java we can do the following

functiontester@ubuntu:~/testfunction$ fn init --runtime java hello
Creating function at: /hello
Runtime: java
Function boilerplate generated.
func.yaml created.

This command will create a subdir called hello (or whatever you gave as the last parameter to the fn init command). Inside that directory you will find the following if you open the folder as a project in IntelliJ.

What you get

So what are you looking at? Well, from a Java developers perspective it's looking quite like a standard maven project, with a pom.xml file and a src folder for you code and tests. The only out of place part, is the func.yaml file, so let's have a quick look at it.

name: hello
version: 0.0.1
runtime: java
cmd: com.example.fn.HelloFunction::handleRequest
build_image: fnproject/fn-java-fdk-build:jdk9-1.0.59
run_image: fnproject/fn-java-fdk:jdk9-1.0.59
format: http

So the first couple of values are quite straight forward, we have the name, version and runtime configuration of the project.
Then we have the cmd value is is what tells the runtime what code to call. So in the automatically generated code it's com.example.fn.HelloFunction:: handleRequest as you also can see in the image above from IntelliJ. So when you rename the package, class and method, remember to update this line in func.yaml.

The last lines are information about the build and run containers to use, and what format the input to the container is.

TIP
If Java isn't your cup of tea, the CLI tool supports other runtimes as well. At the time of writing, these runtimes are listed
dotnet, go, java8, java9, java, lambda-nodejs4.3, lambda-node-4, node, php, python, python3.6, ruby, rust and kotlin

The fn init command also has a lot of options that can be specified, check them out to tune the generated output from the command.

Build and run the code

Now that we have some code, lets run it and see it in action. If you just want to run your code, you can run the following command, or the next one to pass an argument to the function

functiontester@ubuntu:~/testfunction/hello$ fn build

functiontester@ubuntu:~/testfunction/hello$ fn run
Building image hello:0.0.1 .
Hello, world!

functiontester@ubuntu:~/testfunction/hello$ echo -n "Universe" | fn run
Building image hello:0.0.1 .
Hello, Universe!

As you might have guessed, this only does a onetime invocation and shuts down the container. Once we are happy with our function, we would like to deploy it so that it is callable by others. So in order to deploy to our local serverless platform we can do the following.

functiontester@ubuntu:~/testfunction/hello$ fn deploy --app myapp --local
Deploying hello to app: myapp at path: /hello
Bumped to version 0.0.2
Building image hello:0.0.2 .
Updating route /hello using image hello:0.0.2...

This time no output from the function is shown, and instead the function has been deployed. In our deploy command we gave an app argument. This can be used if you have multiple functions that you want to group together.
But where is our app deployed? Well it is now running and available under the following URL, http://localhost:8080/r/myapp/hello As you can see, the value we gave to the app argument is a part of the url, as well as the project name itself. So now go can go there with curl or your browser or any tool that can access an http resource. If you go there with a browser it will look something like this.

App web output

Conclusion

So now you have a running setup with you very own function deployed and available, and you can go ahead and modify the code and play with it's capabilities. It is very easy to get started and get things up and running locally, so you shouldn't have any difficulty with following this guide.

Some of the runtimes have FDK's available that you can use to utilize different parts of the platform. One cool feature is the ability to use different types of data bindings, which will make it easier to use POJO's as input and output of your function. You can also have asynchronous invocations of your functions, and there is a separate project to do orchestration between functions called Fn Flow. My advice is to look around the Fn projects github repo to see what is available for you runtime and other tips and tricks.

I hope to look into setting up and deploying the function project to an Kubernetes cluster some time soon, so look out for a post about that.