Build a Serverless Golang Function with OpenFaaS

In this post I want to show you how to build a Serverless function in Go with our new Golang template created with love by the OpenFaaS community.

OpenFaaS is the only Serverless framework which puts containers in the spotlight and allows any code or binary for Linux or Windows to become a serverless function.

Pre-reqs

  • Go 1.8.3 or later
  • OpenFaaS

This guide assumes you have already deployed OpenFaaS on your laptop or the cloud.

You can deploy OpenFaaS by following the Swarm or Kubernetes guides here:

OpenFaaS Deployment guides

Go

Go (golang) is well suited to writing serverless applications because it has a modern set of libraries covering everything from Marshaling to HTTP to Image Manipulation and much more. This results in concise code which is easy to understand and also offers a simple API for concurrency through channels.

Your code can compile down to a small binary with no other external runtimes required - it can offer C-like speed and power but with type-safety.

We'll use a quick example of a project called structhash which generates a hash in a string format of arbitrary structs. This is useful for creating checksums and hashes of graphs within memory.

structhash is a Go library for generating hash strings of arbitrary data structures.

From the QuickStart:

package main

import (  
    "fmt"
    "crypto/md5"
    "crypto/sha1"
    "github.com/cnf/structhash"
)

type S struct {  
    Str string
    Num int
}

func main() {  
    s := S{"hello", 123}

    hash, err := structhash.Hash(s, 1)
    if err != nil {
        panic(err)
    }
    fmt.Println(hash)
    // Prints: v1_41011bfa1a996db6d0b1075981f5aa8f
}

Let's get started

So let's grab the OpenFaaS CLI and create a new Go function using the language template:

  • Install with curl for the latest version, or with brew
$ curl -sL cli.openfaas.com | sudo sh

If you already have the CLI then run the command again so that you're up to date and in-sync.

  • Create a function from a template

Use faas-cli new to create a template in one of the supported languages, or faas-cli new --lang Dockerfile to use a custom Dockerfile.

  • Create a folder for your functions
$ mkdir -p $GOPATH/src/functions && \
  cd $GOPATH/src/functions

Then use the CLI:

$ faas-cli new --lang go gohash
Folder: gohash created.  
  ___                   ___              ___  
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___| 
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \ 
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|___ / 
      |_|                                     

Function created in folder: gohash  
Stack file written: gohash.yml  

We now have a folder called gohash with a handler.go file inside:

package function

import (  
    "fmt"
)

// Handle a serverless request
func Handle(req []byte) string {  
    return fmt.Sprintf("Hello, Go. You said: %s", string(req))
}

You can see the input is of type []byte which means you can also deal with binary data, or just convert this to a string as we are doing above.

  • Vendor the library

Let's go ahead and vendor the dependency of github.com/cnf/structhash

Install Go's vendoring tool dep:

$ go get -u github.com/golang/dep/cmd/dep

dep needs Golang 1.8 or later, if you can't update from Golang 1.7 or 1.6 then please try another vendor tool like: vndr.

Invoke vendoring on the library:

$ dep init && \
  dep ensure -add github.com/cnf/structhash

Vendoring is Golang's approach to dependency management. It involves copying the entire source tree of any dependent projects into your project.

You'll now see these new files:

Gopkg.lock Gopkg.toml ./vendor  

A copy of the library is copied inside the vendor folder.

Now let's update the code, build, deploy and invoke it.

  • Update gohash/handler.go:
package function

import (  
    "fmt"
    "github.com/cnf/structhash"
)

type S struct {  
    Str string
    Num int
}

// Handle a serverless request
func Handle(req []byte) string {  
    s := S{string(req), len(req)}

    hash, err := structhash.Hash(s, 1)
    if err != nil {
        panic(err)
    }
    return fmt.Sprintf("%s", hash)
}

The code populates our request and its length into the struct ready to be turned into a hash.

Build and deploy:

$ cd $GOPATH/src/functions
$ faas-cli build -f gohash.yml && \
  faas-cli deploy -f gohash.yml

When you're ready invoke it with some input:

$ echo "Serverless" | faas-cli invoke gohash
  • Rinse-repeat

Now just edit your handler.go file and run faas-cli build followed by faas-cli deploy for each change.

A note on pushing: If you're using a remote cluster you will also need to run faas-cli push so the function can be deployed on any available host.

As part of the build we check that your formatting is correct according to the Golang standard. An easy way to get correct formatting is to run the gofmt tool or to use an IDE like VSCode.

$ gofmt -s -w gohash/handler.go

If you head over to http://localhost:8080/ you will also be able to invoke the function through the built-in UI and at http://localhost:9090 you will see all the metrics which have been recorded automatically through Prometheus.

  • Want to go deeper?

Checkout the Dockerfile in the "template/golang" folder which uses Alpine Linux and multi-stage builds to produce a tiny function image.

Test everything

We've included a unit test in this post along with the sample function. So any tests you have in the function's folder are run and validated as part of your build. If you haven't quite mastered unit testing in Go you can delete the file or head over to my tutorial:

gohash/handler_test.go

package function

import "testing"

func TestHandleReturnsCorrectResponse(t *testing.T) {  
    expected := "v1_b8dfcbb21f81a35afde754b30e3228cf"
    resp := Handle([]byte("Hello World"))

    if resp != expected {
        t.Fatalf("Expected: %v, Got: %v", expected, resp)
    }
}

Wrapping up

We've just build a native Golang function and deployed it to OpenFaaS including vendored dependencies. OpenFaaS supports any process or code as a function but our unique templates mean you can get to serverless even faster.

"Function templates" - from my presentation at JeffConf Milan

Did you know OpenFaaS won the InfoWorld award for Best Cloud Software 2017?

Star the OpenFaaS repo and find out why so many people are choosing OpenFaaS - the only Cloud Native Serverless framework for Kubernetes and Docker Swarm.

See also:

Mentions: thank you to Richard Gee for proof reading and testing these instructions.

Alex Ellis

Read more posts by this author.

United Kingdom http://alexellis.io/

Subscribe to alex ellis' blog

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!