There’s now a better way to do this! See here: http://jamesthom.as/blog/2017/01/17/openwhisk-and-go/
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
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.
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.
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 path.
1 2 3 4
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
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.
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.
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.
1 2 3
Re-writing the “reverse string” Action above to use this package is shown here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
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.
1 2 3 4
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.