Function as a Service - A Go+Docker implimentation
So this docker thing seems to be getting some traction, and so does function as a service (FaaS). It would be nice if we could have our own FaaS infrastructure in place instead of paying Amazon for it. There are some alternatives out there e.g. OpenFaaS. But we have a bad case of “Not Invented Here” syndrome, so we built one ourselves.
This is a small GoLang infrastructure app that enables one to deploy simple REST servers, acting as single functions. The goal was to deploy and scale the functions horizontally with ease. To achieve this, we leveraged the scaling and service discovery that comes for free in a docker-compose and swarm.
The core component is the FaaS Gateway. The image above illustrates the idea. The gateway uses docker to discover function dynamically and updating an internal table, a table of functions, and the containers providing them. When the gateway receives the request: GET lambda/function-3?param-1=123¶m-2=456
redirect the request containers with the tag faas:name=function-3
in a round-robin fashion.
Creating your function
A function service is micro-service executing a single golang function.
Creating a function service is straight forward using the faas/function
library.
/go/src/github.com/pintjuk/faas/addition/addition.go:
import (
"github.com/pintjuk/faas/function"
)
func main() {
function.RunFunc([]string{"a", "b"},
func(a float64, b float64) float64 {
return a + b
},
":8080")
}
Just pass any GoLang function to RunFunc, and the library will spin up a web server running this function. It will automatically detect the number of parameters and map them to query parameters ?param-1¶m-2& ...¶m-n
of the incoming requests.
To make it work with the FAAS-Gateway, you need to deploy it in a docker container with the following labels:
faas.name={name of your function}
faas.port={the port you used for its web server}
With these labels, the FAAS gateway will detect your function container automatically and start forwarding function calls to it as soon as your container is up.
This is a docker file for the example function addition function above:
addition/Dockerfile:
FROM golang:1.9
# install govender and fswatch
RUN go get -u github.com/kardianos/govendor
RUN mkdir -p /go/src/github.com/pintjuk/faas/addition
WORKDIR /go/src/github.com/pintjuk/faas/addition
EXPOSE 8080
CMD govendor fetch +m ; go run cmd/*/*.go
And this is its docker compose entry:
docker-compose.yml:
addition:
build:
context: ./addition
labels:
- "faas.name=addition"
- "faas.port=8080"
volumes:
- ./addition:/go/src/github.com/pintjuk/faas/addition
This is the folder structure for this example:
├── README.md
├── addition
│ ├── Dockerfile <- docker file for fuction
│ └── cmd
│ └── additiond
│ └── addition.go <- function source
├── docker-compose.yml <- compose file
Installation
Requirements
- Docker
- Docker-compose
- Govendor
Installation steps
- Install GoLang.
- Install docker and docker-compose.
Install Govendor:
go get -u github.com/kardianos/govendor
Clone this repo:
git clone https://github.com/kardianos/govendor.git
Running FaaS
up faas-gateway and function services
cd faas docker-compose up