Getting Started with OpenFaas Part 2 (Custom Functions)

·

5 min read

In Part 1 we deployed OpenFaaS on local kubernetes and ran few functions. In this part we will create, deploy and run custom functions and dive into the serverless architecture.

At the end of this you will have a serverless function deployed that returns the list of animals with /animals and individual animal details with /animals/bear when requested

Lets get started !

Overview

Function Templates

All functions in OpenFaaS are created from a template. The OpenFaaS CLI has a template engine built-in which helps create new functions in the desired programming language. The way this works is by reading a list of templates from the ./template location in your current working folder.

To list the templates run the following command

$ faas-cli template store list

This will list the templates from the known stores. To pull any template you can use the pull option. For e.g. for pulling the python3-http template which we will be using run the following command

$ faas-cli template store pull python3-http

Classic vs. of-watchdog Templates

OpenFaaS interacts with the functions through watchdogs. Every template runs the watchdog and provide the basic skeleton for development of the function.

There are 2 different types of watchdogs

  • Classic Watchdog which uses STDIO to communicate with your function.
  • of-watchdog uses HTTP to communicate with functions

The python3-http template uses the of-watchdog.

Create Custom Function

So with the templates in place lets create a function with the following command

$ faas-cli new --lang python3-http animals

This will create a yml file and a directory

  • ./animals.yml
  • ./animals/

The .yml file is used to configure the CLI for building and deploying the function. Open and edit the gateway URL in the .yml if it is incorrect.

The animals/handler.py file is where the function implementation will reside. The contents of the file look like

def handle(event, context):
    return {
        "statusCode": 200,
        "body": "Hello from OpenFaaS!"
    }

This function when invoked will return the status code as 200 with body as "Hello from OpenFaaS!"

Build Custom Function

Before we build the function as you would have noticed inside the animals directory there is file handler_test.py. This is useful for running the unit tests that we can write. But that is out of scope for the current exercise.

To disable tests from running every time edit the animals.yml file and add build_args section as below :

version: 1.0
provider:
  name: openfaas
  gateway: http://127.0.0.1:31112
functions:
  animals:
    lang: python3-http
    handler: ./animals
    image: animals:latest
    build_args:
      TEST_ENABLED: false

Now build the custom function by running the command

$ faas-cli build -f animals.yml

This will build the docker image for the function which we can then deploy

Deploy Custom Function

Before we deploy the function we will have to make few config changes to openfaas. The default behavior of faas-netes is to always pull the latest chart from the docker registry. Since we have not push it to docker and we don't want to unnecessarily push and pull the image we update the helm to pull only when necessary.

The deployment should have default used openfaas as the namespace. In case it is using a different namespace edit the -n option accordingly

$ helm upgrade openfaas openfaas/openfaas --install --set "faasnetes.imagePullPolicy=IfNotPresent" -n openfaas

In case you see some error check if helm is correctly installed and available in the path. Try restarting the terminal and retry.

Now we are ready to deploy the function

$ faas-cli deploy -f animals.yml

The function should now be visible on the openfaas gateway UI. Invoke the function (you can also use curl command to invoke as below)

$ curl http://localhost:31112/function/animals

Replace localhost:31112 with the openfaas gateway URL

And Viola ! you should see the response as Hello from OpenFaaS!

Implement Custom Function

Now that we have a hello-world function up and running lets implement the logic.

The handler.py file has one function named handle(event, context) which will be called by the openfaas whenever this function is invoked. Different templates would different args to the function depending on the template skeleton implementation. But basically every template would have one entry point via the handle function.

The python3-http template handle function receives args as event - the request params and context - flask context. It expects a response as a dictionary with statusCode, body, headers, etc all optional.

Edit the handler.py file and replace it with below:

import logging

# configure logging
logging.basicConfig(level=logging.DEBUG)

# define sample data
data = {
    "lion": {
        "domesticated": False
    },
    "bear": {
        "domesticated": False
    },
    "dog": {
        "domesticated": True
    },
    "cat": {
        "domesticated": True
    }
}

def handle(event, context):
    # define response
    res = {
        "statusCode": 404,
        "body": "Not Found"
    }

    # Message will be visible in kubernetes container logs
    logging.debug("Event %s", event.__dict__)

    # check is path is empty then return everything else return requested path
    if event.path != "/":
        path = event.path.strip("/")
        details = data.get(name, None)
        if details is not None:
            res = {
                "statusCode": 200,
                "body": details
            }
    else:
        res = {
            "statusCode": 200,
            "body": data
        }

    return res

Here we create sample data in the data variable. Then based on the path we return the requested data. If the path is invalid we return status as 404.

Lets see this in action

$ curl http://localhost:31112/function/animals
{"bear":{"domesticated":false},"cat":{"domesticated":true},"dog":{"domesticated":true},"lion":{"domesticated":false}}

Now lets fetch only the lion details

$ curl http://localhost:31112/function/animals/lion
{"domesticated":false}

What is we give some invalid animal ?

$ curl http://localhost:31112/function/animals/invalid
Not Found

Now it is not difficult to implement the function to talk to a database, is it ?

Till next time. Have a nice day !

Did you find this article valuable?

Support PrSh9 by becoming a sponsor. Any amount is appreciated!