Personal Discovery Journey Into Code-World: FaaSD and OpenFaaS

Personal Discovery Journey Into Code-World: FaaSD and OpenFaaS

Regularly, I discover myself thinking "wow, that's so simple I can build this in a weekend". My rational brain kicks in at some point: "Waaaaiiit a second, if it's so simple, why am I not seeing this done a million times?". Here I usually start better scoping and either find the answer to my question.

Often, my developer mind insists on "it's actually just two API endpoints and then I could do this and that". And often this holds true for the core functionality. If some basic validation gives a green light for working on it from a commercial perspective, I still need to consider the tech stack and marketing approach, as building alone doesn't do it.

I'm not super fixed on the approach, my main goal is usually to keep long term overhead low. Laravel is my go-to solution for anything backend-heavy, but its power comes at a complexity cost too. For two little API endpoints used in, for example, a browser extension is a bit of an overkill.

Function as a service sounds like a great step towards "just having a few API endpoints". AWS Lambda is the name everyone is having in mind here. But any gains from simplicity are eaten up by AWS complexity. If you are new to AWS (Lambda), it easily takes you double or more time to get it running as you spend building the little lean function in the first place. This doesn't go well with the plan to "just chuck this out over the weekend".

Enter: faasd

Function as a Service should be easy. Here comes faasd into play. It's a self-hosted alternative to run functions. It allows you to run a simple copy & paste installer script on your machine getting it up and running. It takes less than ten minutes to get to work. It's production-ready and helps to remove the learning curve involved with Kubernetes and co.

faasd is a self-hosted alternative to AWS Lambda to run functions. Production-ready within minutes ⏲️

Once you have deployed your faasd instance, it's a matter of one command to push your function into production. From there it's up to you what you like to build. I catch myself breaking up the structure of larger applications in functions. It builds the container, publishes, and deploys your function code ready-to-use in seconds. To run this you will need the FaaS CLI. Again this is installed in under one minute thanks to copy and paste that just works.

Found a great library but it's written in the "wrong" language? Thanks to the flexibility, you can also jump between programming languages easily. I use a mix of nodejs, PHP, and Python by now.

With functions you libraries aren't in the wrong language anymore.

This helps to truly break up large applications into functional parts using the best tool for you. You can get a rich list of the official templates by running:

$ faas-cli template store list

NAME                     SOURCE             DESCRIPTION
csharp                   openfaas           Classic C# template
dockerfile               openfaas           Classic Dockerfile template
go                       openfaas           Classic Golang template
java8                    openfaas           Java 8 template
java11                   openfaas           Java 11 template
java11-vert-x            openfaas           Java 11 Vert.x template
node12                   openfaas           HTTP-based Node 12 template
node                     openfaas           Classic NodeJS 8 template
php7                     openfaas           Classic PHP 7 template
python                   openfaas           Classic Python 2.7 template
python3                  openfaas           Classic Python 3.6 template
python3-dlrs             intel              Deep Learning Reference Stack v0.4 for ML workloads
ruby                     openfaas           Classic Ruby 2.5 template
ruby-http                openfaas           Ruby 2.4 HTTP template
python27-flask           openfaas           Python 2.7 Flask template
python3-flask            openfaas           Python 3.7 Flask template
python3-flask-debian     openfaas           Python 3.7 Flask template based on Debian
python3-http             openfaas           Python 3.7 with Flask and HTTP
python3-http-debian      openfaas           Python 3.7 with Flask and HTTP based on Debian
golang-http              openfaas           Golang HTTP template
golang-middleware        openfaas           Golang Middleware template
python3-debian           openfaas           Python 3 Debian template
powershell-template      openfaas-incubator Powershell Core Ubuntu:16.04 template
powershell-http-template openfaas-incubator Powershell Core HTTP Ubuntu:16.04 template
rust                     booyaa             Rust template
crystal                  tpei               Crystal template
csharp-httprequest       distantcam         C# HTTP template
csharp-kestrel           burtonr            C# Kestrel HTTP template
vertx-native             pmlopes            Eclipse Vert.x native image template
swift                    affix              Swift 4.2 Template
lua53                    affix              Lua 5.3 Template
vala                     affix              Vala Template
vala-http                affix              Non-Forking Vala Template
quarkus-native           pmlopes            Quarkus.io native image template
perl-alpine              tmiklas            Perl language template based on Alpine image
crystal-http             koffeinfrei        Crystal HTTP template
rust-http                openfaas-incubator Rust HTTP template
bash-streaming           openfaas-incubator Bash Streaming template
cobol                    devries            COBOL Template

There are also inofficial templates you can find with a bit of research on GitHub.

Start with a new function by running:

faas-cli new function-name --lang node12

This creates a function based on the node12 template. Now you can develop the function in the handler.js-file. This approach works similarly for all other functions. Once you ready run faas-cli up to deploy the function.

Building a Function

I like to learn by doing. So I started by building a simple function to detect the language of a given string. The whole function including access control is only 31 lines with plenty of space:

'use strict'

const fs = require('fs')
const fsPromises = fs.promises
let franc = require('franc')

module.exports = async (event, context) => {
  // Check the auth token
  let secret = await fsPromises.readFile("/var/openfaas/secrets/franc-token", "utf8")
  let auth = event.headers["authorization"]
  if(!auth && auth != "Bearer: " + secret) {
    return context
      .status(403)
      .headers({"Content-Type": "application/json"})
      .succeed({"status": "Unauthorized"})
  }

  let response = {}
  if (event.query.query == undefined || event.query.query.length == 0) {
    response.status = 'Error'
    response.message = 'No query string provided'
  } else {
    response.status = 'Success'
    response.result = franc.all(event.query.query).splice(0, 10)
  }

  return context
    .status(200)
    .headers({"Content-Type": "application/json"})
    .succeed(response)
}

Functions as a service are made for this: You can easily try out a library or different programming language as it's made to be disposable. Don't like how it's going? Drop it, delete the function and your system is clean once more. No compilers, dependencies, and other tooling remain on your system.

Lessons learned along the way

At the beginning, I didn't want to run my own container registry. I expected additional overhead and "another thing to maintain". This turned out to be a mistake, as the setup was almost as easy as faasd itself. Plus, the performance is much better than relying on Docker Hub.

I got it up and running on my Hetzner server in a few minutes using some guides from DigitalOcean.

After spinning up your server, the steps break down to:

Another really interesting option is arkade. It allows you to abstract the steps.

I should have also paid closer attention to the OpenFaaS workshop at the beginning. It guides you through the basics with examples better than purely self-discovery does. This is especially true for me, as I'm not deep in the serverless space.

Worry about scaling, when you get to scale

As with any solution approach, there are limitations. For the most time, I leave these concerns out. It simply doesn't matter if my functions can scale to millions of users, as I don't have millions of users. Migrating to a more scalable approach such as OpenFaaS Cloud should be very doable.

Worry about scaling, when you get to scale. Until then build and market.

Community: The People

We can probably agree: The people behind a project matter to its success for a large part. The OpenFaaS project is driven by Alex Ellis, a passionate developer. He and the contributors maintain an active slack channel - questions from newbie-level to expert find answers there. Alex is supporting this effort with contracting, but other options such as sponsorship of OpenFaaS or Alex directly are available (and recommended).

Get Playing

As with any reading: It can only take you so far. Make sure to put a few hours aside and check out faasd! It does come with a little overhead to learn and keep up. Especially for independent developers eyeing to monetize an API or build a small SaaS this could be a great solution.