# Simple Serverless with Golang Functions and Microservices

## In this post Alex will explore what a Serverless function and microservice look like in Golang with OpenFaaS. We'll see how the OpenFaaS templates abstract away boilerplate code and how to start building your own templates.

April 10, 2019

---

In my [previous post](/content/blog/openfaas-cloudrun/index.html) I demonstrated how the OpenFaaS CLI and build-templates can enable functions on any container orchestrator such as Kubernetes or Google Cloud Run. In today’s post I will focus on how to deploy your Golang code to OpenFaaS either as a function or as a stateless microservice.

## What is serverless?

In 2016 I introduced [Functions as a Service (FaaS)](https://blog.alexellis.io/functions-as-a-service/) as a set of behaviours and properties:

Serverless & FaaS:

- tends to involve invoking short-lived functions (Lambda has a default 1-sec timeout)
- does not publish TCP services - often accesses third-party services or resources
- tends to be ad-hoc/event-driven such as responding to webhooks
- should deal gracefully with spikes in traffic
- despite name, runs on servers backed by a fluid, non-deterministic infrastructure
- when working well makes the complex appear simple
- has several related concerns: infrastructure management, batching, access control, definitions, scaling & dependencies

Since then I went on to build out a more refined serverless contract for containers:

Has a simple HTTP contract on port 8080  
 Is packaged in containers  
 Runs functions OR microservices  
 Can use any 64-bit Linux binary or HTTP server  
 Auto-scales on QPS, even to zero  
 Started over 2.5 years ago

Name this [#serverless](https://x.com/hashtag/serverless?src=hashtag_click) framework?

## Tutorial

Here we’ll show you how to build a function using two of the available templates and compare the differences. We’ll then show you how to construct a microservice followed by how we could get the best of both worlds using a Golang middleware template.

I will be using the OpenFaaS CLI which is available via `brew install faas-cli`, [GitHub releases](https://github.com/openfaas/faas-cli/) or on Linux/Mac with:

```bash
# use `sudo sh` to move to /usr/local/bin/
curl https://cli.openfaas.com | sh
```

### Golang Function template (classic)

The classic Golang template for OpenFaaS forks one process for every incoming request meaning that state is not retained between invocations. This is a similar model to cgi-bin and uses UNIX STDIO pipes to send the request to the function and to retrieve the response.

Before OpenFaaS had the concept of templates, every function or microservice had its own Dockerfile and entrypoint code. When this template was announced it greatly improved the developer experience of both writing and maintaining code.

```bash
$ faas-cli new --lang go classic-go

Function created in folder: classic-go
Stack file written: classic-go.yml

Notes:
You have created a new function which uses Golang 1.10.4
To include third-party dependencies, use a vendoring tool like dep:
dep documentation: https://github.com/golang/dep#installation
```

You’ll get a handler which looks like this:

```go
package function

import (
	"fmt"
)

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

You don’t need to manage a Dockerfile or worry about health checks or reading HTTP request and response objects. Your HTTP request headers are available via environment variables if required such as `Http_Path` and `Http_X_Custom_Header`

A YAML stack file is also generated for each function and can be used to build multiple functions in parallel, which adds value to the Docker toolchain.

_classic-go.yml_

```yaml
provider:
  name: openfaas

functions:
  classic-go:
    lang: go
    handler: ./classic-go
    image: classic-go:latest
```

To add additional functions to the YAML file just pass `--append classic-go.yml` to `faas-cli new`.

This original Go template is widely used and is maintained for backwards compatibility.

### Golang Function template (HTTP)

A newer template was developed to give full access and control to the underlying HTTP request and response. This template also moves from using STDIO to HTTP so that database connections can be persisted across invocations. It also allows data to be loaded into memory or cached between requests.

To use this template just pull it from the [template store](/content/blog/template-store/index.html).

```bash
$ faas-cli template store pull golang-http
$ faas-cli new --lang golang-http http-go
```

You’ll see a slightly different signature which makes the HTTP request and response available through an object instead of environment variables:

_handler.go_

```go
package function

import (
	"fmt"
	"net/http"

handler "github.com/openfaas/templates-sdk/go-http"
)

// Handle a function invocation
func Handle(req handler.Request) (handler.Response, error) {
	var err error

message := fmt.Sprintf("Hello world, input was: %s", string(req.Body))

return handler.Response{
		Body:       []byte(message),
		StatusCode: http.StatusOK,
	}, err
}
```

See also: [golang-http README](https://github.com/openfaas/golang-http-template) for examples of how to use a database connection and HTTP paths.

## Golang Microservice

### Existing Docker image

If you already have a Golang microservice then you can convert it to be built by the `faas-cli` tool-chain or simply add it to your function’s YAML file.

The `skip_build` flag will allow the service to be deployed without the `faas-cli` trying to also build it for you. This method is also useful when consuming third-party functions.

```yaml
provider:
  name: openfaas

functions:
  customer-service:
    image: docker.io/org/customer-service:0.1.0
    skip_build: true
    labels:
      com.openfaas.scale.min: 1
      com.openfaas.scale.max: 10
```

See also: [YAML stack file reference](https://docs.openfaas.com/reference/yaml/)

### New service using a Dockerfile

If you want to build your own Dockerfile and host your own HTTP server then you can do the following using the `dockerfile` template:

```bash
$ faas-cli new --lang dockerfile go-microservice
```

This will create `go-microservice.yml` and the folder `go-microservice`. Simply copy your Dockerfile and source code into the folder.

Let’s look at how much code we’d need for a middleware handler, `Dockerfile` and `main.go` entrypoint.

```dockerfile
FROM golang:1.10.4-alpine3.8 as build

RUN mkdir -p /go/src/handler
WORKDIR /go/src/handler
COPY . .

RUN CGO_ENABLED=0 GOOS=linux \
    go build --ldflags "-s -w" -a -installsuffix cgo -o handler . && \
    go test $(go list ./... | grep -v /vendor/) -cover

FROM alpine:3.9
# Add non-root user and certs
RUN apk --no-cache add ca-certificates \
    && addgroup -S app && adduser -S -g app app \
    && mkdir -p /home/app \
    && chown app /home/app

WORKDIR /home/app

COPY --from=build /go/src/handler/handler    .

RUN chown -R app /home/app

RUN touch /tmp/.lock #  Write a health check for OpenFaaS here or in the HTTP server start-up

USER app

CMD ["/home/app/handler"]
```

The middleware will simply inject a HTTP header of `X-Served-Date` with the date the request was processed.

```go
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func addServedHeader(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("X-Served-Date", time.Now().String())
}

func makeRequestHandler(middleware http.HandlerFunc) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		middleware(w, r)

w.Write([]byte("OK"))
	}
}

func main() {
	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", 8080),
		ReadTimeout:    3 * time.Second,
		WriteTimeout:   3 * time.Second,
		MaxHeaderBytes: 1 << 20, // Max header of 1MB
	}

next := addServedHeader
	http.HandleFunc("/", makeRequestHandler(next))
	log.Fatal(s.ListenAndServe())
}
```

Now run `faas-cli up -f go-microservice.yml` and invoke the service:

```bash
$ curl -i http://127.0.0.1:8080/function/go-microservice ;echo
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: text/plain; charset=utf-8
Date: Wed, 10 Apr 2019 15:08:46 GMT
X-Call-Id: 0b441f6e-8afa-4d82-80dd-48206b1e0e3e
X-Served-Date: 2019-04-10 15:08:46.215153582 +0000 UTC m=+21.331669185

OK
```

You’ll now be able to invoke your function and see the additional header added. We got to build our own Dockerfile and use the Golang HTTP stdlib which is something you don’t usually see in the world of FaaS frameworks.

### Golang middleware template

Now if that all felt a little excessive and repetitive to you, then don’t worry because you’re not the only one. Imagine what that would look like with several dozen of those services? Now what if you need to fine-tune the code in one of the Dockerfiles or update a component?

Fortunately the community came up with a third solution which combines the best parts of the Golang HTTP stdlib and OpenFaaS templates. Let’s look at the example above using the `golang-middleware` template.

```bash
$ faas-cli template store pull golang-middleware
$ faas-cli new --lang golang-middleware go-middle
```

_handler.go_

```go
package function

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func Handle(w http.ResponseWriter, r *http.Request) {
	var input []byte

if r.Body != nil {
		defer r.Body.Close()

body, _ := ioutil.ReadAll(r.Body)

input = body
	}

w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf("Hello world, input was: %s", string(input))))
}
```

This is the standard example with further examples on the README for the `golang-http` template linked above.

```go
package function

import (
	"net/http"
	"time"
)

func Handle(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("X-Served-Date", time.Now().String())
	w.Write([]byte("OK"))
}
```

Now you can run `faas-cli up -f go-middle.yml` and test the new endpoint. You’ll see that it’s functionally equivalent but the maintenance of dozens of similar functions will be trivial compared to tending to boilerplate code.

## Custom templates

The easiest way to start building your own template is to checkout some of the examples available from the community in the [template store](https://github.com/openfaas/store) or the [Official Classic templates](https://github.com/openfaas/templates/). And remember the [OpenFaaS workloads](https://docs.openfaas.com/reference/workloads/) contract.

If you have a binary, HTTP server or shell script that runs on Linux, then the chances are you can package and deploy it with OpenFaaS for a highly scalable, fault-tolerant serverless experience on any cloud.

## Wrapping up

A goal of Serverless and FaaS is to reduce boilerplate code and process so that you can focus on shipping code instead of worrying about infrastructure.

OpenFaaS provides a flexible templating system and build process through the use of the Docker image format and its user-friendly `faas-cli`. We saw several examples of how to package a Golang function and a Golang microservice into containers for use with OpenFaaS.

You can learn how to deploy OpenFaaS to Kubernetes and build functions and microservices using the [OpenFaaS workshop](https://github.com/openfaas/workshop/).

> OpenFaaS is written in Go. Checkout my new book [Everyday Go](http://store.openfaas.com/l/everyday-golang?layout=profile) for practical tips and hands-on examples to gain experience quickly or to level-up.

### Join the community

The OpenFaaS community values are: developers-first, operational simplicity, and community-centric.

If you have comments, questions or suggestions or would like to join the community, then please [join us on the weekly Office Hours call](https://docs.openfaas.com/community/).

You can [follow me @alexellisuk](https://twitter.com/alexellisuk/) and [@openfaas on Twitter](https://twitter.com/openfaas/)
