Fn Hot Docker Functions

Shaun Smith
Fn Project
Published in
4 min readOct 4, 2018
Eruptive Trio Seen by STEREO, Copyright © 2010 NASA, Attribution 2.0 Generic (CC BY 2.0)

Ideally, an Fn function should be “hot”. With a hot function, the function container is started and kept alive to process a series of function invocations. Hot functions are great because there’s a cost to starting a container — the Fn server has to pull the image from a repository if the image isn’t cached locally, start the container, and typically boot the language runtime inside the container before it can even start handling function calls. With a hot function you only pay these “cold start” pull/start/boot costs on the first invocation. Latency on subsequent invocations is dramatically lower. So naturally you should always deploy a hot function, right? Unfortunately, it’s not so straight forward if you’re deploying a Docker container as a function — but there is a way!

If you’re using any of the Fn Function Development Kits (FDKs) hot functions are a breeze. In fact, you are probably using an FDK and didn’t really think about whether your function was hot or not. You included the FDK library in your application, wrote your handler function (or method), and passed your handler to the FDK. The fact that the container is kept alive and that the FDK is providing a request loop listening for incoming function invocations may not be obvious. But that’s what’s happening.

If you aren’t using an FDK then you’re running your function with the “default” (i.e., “not hot”) container contract. With default, a container is started for each function invocation, input is piped into the container on stdin, the response read from stdout, and then it’s shutdown. It works but doesn’t provide the low latency response time of a hot function.

Hot Docker

In addition to support for popular languages through FDKs, Fn supports deployment of Docker containers as functions. This is a major differentiator when compared to many other functions-as-a-service platforms. Fn lets you deploy anything as a function as long as your container implements one of the supported container contracts. Fortunately, the default stdin/stdout container contract is easy to implement in your custom containerized function. For example, here’s a Dockerfile that packages up a Node.js program as a container image that can be deployed to Fn as a function.

NOTE: This example is just for illustration purposes and you should really be using the Fn Node FDK for optimal Node.js performance!

And here’s thefunc.yaml file that allow you to build this function with fn build. Notice that the (container contract)format is default and runtime is set to docker rather than java, node or one of the other languages supported by Fn.

So with these three files you can deploy a default container contract function. But this function won’t have the low latency it would have if it were a hot function. On each invocation you will pay the container and Node.js runtime startup costs. If I deploy to a local Fn server and invoke this function with time I see a response time of around 1.3 seconds. That’s pretty bad, but not an entirely surprising amount of time to start a Docker container on a Macbook.

“Hotwrap” Prototype

It would be much better if I could run this code as a hot function. Fortunately, to make it easier to deploy non-FDK functions as hot functions a prototype utility with codename “hotwrap” is currently being developed. Hotwrap implements the hot function container contract and executes your stdio-based function each time the function is invoked. Using hotwrap, the function container is kept alive so you avoid container startup costs — although you still pay the cost to start your function executable on each invocation.

To use hotwrap you simply set the hotwrap executable as the ENTRYPOINT of your container and provide theCMD to launch your function executable. The Dockerfile below illustrates the changes required to add hotwrap to the Node.js example above.

NOTE: This example uses a multi-stage Docker build to obtain the hotwrap executable from a Docker image which currently is not yet published in Docker Hub. You can build this image yourself from the sources on GitHub.

With this updated Dockerfile we can redeploy the Node.js function and take some new timings. On the first invocation, time reports 0.775 seconds to execute the function. This elapsed time includes the cost of starting the container and Node.js. For subsequent invocations, time reports around 0.2 seconds which is a significant 0.5 seconds faster! Thanks to hotwrap we’re only paying the cost of starting the Node.js runtime and running our code.

The future of Hotwrap

Hotwrap is a prototype so don’t use it in production! But it has demonstrated the feasibility and value of providing a mechanism in Fn that improves the runtime performance of programs packaged as functions that were not originally written as functions. While Fn has always supported the deployment of Docker containers as functions, those functions used the default container contract and incurred higher latency costs. Hotwrap partially addressed the disparity so look for an official (likely renamed) hotwrap utility in Fn in the near future!

Thanks to Owen Cliffe for developing hotwrap!!

--

--