Serverless Go Actions

存储架构 2016-06-22

, the open-source serverless platform, provides the ability to invoke custom Docker
containers as serverless functions.

Developers can create new Actions
, referencing public images on Dockerhub
. OpenWhisk manages creating and executing containers using these images per invocation request.

Using this feature, developers can write serverless functions using the Go language
. Compiled Go language binaries are embedded within custom Docker images and pushed into the platform.

So, how do we start?

This blog post will explain how to get your Go language functions running as “serverless functions” on OpenWhisk. If you’re impatient to get to the code, this repository
contains the examples for everything discussed below.

OpenWhisk helps developers create custom Actions using Docker through an SDK…

OpenWhisk Docker SDK

Using the
command-line utility

, developers can install the SDK
into the current directory.

$ wsk sdk install docker

The SDK provides the source for a custom Docker image
, which executes a custom binary in response to invocation requests. The default SDK copies the executable file, located at the client/action
, into the image during the build process. Users build the image locally before pushing this to Dockerhub.

$ docker build -t /docker_action .
$ docker push /docker_action

Using the command-line utility, users can then create a new Action referencing this public Docker image. When this Action is invoked, the platform will spin up a new container from this custom image.

$ wsk action create docker_action --docker /docker_action
$ wsk action invoke --blocking --result docker_action

OpenWhisk Docker Action

OpenWhisk SDK’s Docker image uses a Node.js application
to handle the JSON invocation request from the platform and spawns a process to execute the binary. Invocation parameters are passed as a JSON string through a command-line argument to the binary. The executable must write the JSON response to stdout, the handler will return this to the platform.

Containers used to run OpenWhisk Actions must be expose a HTTP API on port 8080 with two paths, /init
and /run
. The platform sends HTTP POST requests to these paths to initialise the Action and schedule invocations.

The /init
path is used to provide the Action source for languages which support runtime evaluation. User-provided Docker images do not need to implement this method, other than returning a non-error HTTP response.

The /run
path is called by the platform for each invocation request. Parameters for the invocation are passed as the value
property of the JSON request body. Any non-empty JSON response will be interpreted as the invocation result.

Go Actions using the Docker SDK

Using Go binaries with the Docker SDK requires the developer to cross-compile the source for the platform architecture and copy the binary to the client/action

export GOARCH=386
export GOOS=linux
go build -o action
mv action client/action

The Go code must parse the invocation parameters as a JSON string from the command-line argument. Data written to stdout
will be parsed as JSON and returned as the Action response.

This sample Go source demonstrates using this method to implement a “reverse string” Action.

package main

import "os"
import "encoding/json"
import "log"

type Params struct {
  Payload string `json:"payload"`

type Result struct {
  Reversed string `json:"reversed"`

// extract invocation parameters, passed as JSON string argument on command-line.
func params() Params {
  var params Params
  source := os.Args[1]
  buf := []byte(source)
  if err := json.Unmarshal(buf, &params); err != nil {
  return params

// convert struct back to JSON for response
func return_result(result Result) {
  buf, err := json.Marshal(result)
  if err != nil {

func main() {
  input := params()

  // reverse the string passed from invocation parameters
  chars := []rune(input.Payload)
  for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
    chars[i], chars[j] = chars[j], chars[i]
  result := Result{
    Reversed: string(chars),


Docker SDK Base Image

Building a base image from the OpenWhisk Docker SDK and publishing on Dockerhub simplifies the process of building a Docker-based Action. Developers can now use the following image ( jamesthomas/openwhisk_docker_action
), without having to install the SDK locally.

FROM jamesthomas/openwhisk_docker_action
COPY action /blackbox/action

This base image includes the Node.js handler to manage the platform HTTP requests. An executable file at /blackbox/action
will be called for each invocation. JSON parameters and responses are still passed using command-line arguments and stdout.

Custom Go Handler

Using the Docker SDK for OpenWhisk relies on a Node.js application to handle the platform HTTP requests, spawning a process to execute the user binary file.

Implementing the HTTP API, described above, in Go would allow us to remove the Node.js handler from the image. Compiling the Go Action source with the HTTP API handler into a single binary and using an Alpine Linux base image will dramatically reduce the image size.

This should improve execution performance, by removing the Node.js VM process, and cold start-up time, through having a smaller Docker image.

Using this Go package, jthomas/ow
, users can automate the process of creating Go-based Actions.

go get jthomas/ow

The package provides a method for registering Action callbacks and implements the HTTP endpoints for handling platform requests.

Invocation parameters are passed using a function parameter, rather than a raw JSON string. Returned interface values will be automatically serialised to JSON as the Action response.

openwhisk.RegisterAction(func(value json.RawMessage) (interface{}, error) {

Re-writing the “reverse string” Action above to use this package is shown here.

package main

import (

type Params struct {
    Payload string `json:"payload"`

type Result struct {
    Reversed string `json:"reversed"`

func reverse_string(to_reverse string) string {
    chars := []rune(to_reverse)
    for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
        chars[i], chars[j] = chars[j], chars[i]
    return string(chars)

func main() {
    ow.RegisterAction(func(value json.RawMessage) (interface{}, error) {
        var params Params
        err := json.Unmarshal(value, &params)
        if err != nil {
            return nil, err
        return Result{Reversed: reverse_string(params.Payload)}, nil

Cross-compiling the Action source, bundling this package, creates a single lightweight binary.

Embedding this file within a Docker image, using a minimal base image, creates a tiny image (<10MB). Containers from these images only execute a single process to handle both the HTTP requests and running the Action source.

FROM alpine:3.4
COPY action /action
CMD ["./action"]

Pushing the local image to Dockerhub and then using it to create an Action follows the same instructions above.


Running OpenWhisk Actions from user-provided Docker images allows developers to execute “serverless functions” using any language. This is a fantastic feature not currently supported by many of the other serverless providers.

OpenWhisk provides an SDK
letting users build a local Docker image which executes their Action and handles the HTTP requests from the platform. Using this with Go-based Actions
requires us to cross-compile our binary for the platform and handle passing JSON through command-line arguments and stdout.

Re-writing the HTTP handler natively in Go
means the Docker image can contain and execute a single binary for both tasks. Using this Go package
provides an interface for registering Actions and handles the HTTP requests automatically.

This project
contains examples for the “reverse string” Action using both the Docker SDK and Go-based handler detailed above.


Make a Serverless Slack Notification Service – “A ... Lots of people have been chopping up their infrastructures into small single purpose slices known as microservices. Cloud functions, or serverless ...
Birth of the NearCloud: Serverless + CRDTs @ Edge ... Kuhiro 10X Faster than Amazon Lambda This is a guest post by Russell Sullivan , founder and CTO of Kuhirō . Serverless is an emerging ...
A new way of creating realtime services Websocketify (wsify) v2.0 Just a tiny, simple and realtime pub/sub messaging service Why I wanted to create a tiny solution that can repl...
Customizing Docker Images in Cloudera Data Science... This article shows how to build and publish a customized Docker image for usage as an engine in Cloudera Data Science Workbench. Such an image or engi...
数人云|容器5大深坑莫要踩,5种实践出真知... 众所周知,容器已经在很多互联网企业以及传统企业当中实践应用,这种新兴的技术有很多地方会被人误解,一不小心就会踩到坑,本文将讨论这些,因为Docker是被最广泛采用的容器技术,所以以它为例。 Docker的5大误区 误区1:Docker是万灵药 Docker并不解决云端所有的问题,所以在容...