This tutorial walks through how to use a custom Docker image to define an Fn function. Although Fn functions are packaged as Docker images, when developing functions using the Fn CLI developers are not directly exposed to the underlying Docker platform. Docker isn't hidden (you can see Docker build output and image names and tags), but you aren't required to be very Docker-savvy to develop functions with Fn.
What if you want to make a function using Linux command line tools, or a script that does not involve one of the supported Fn languages? Can you use your Docker image as a function? Fortunately the design and implementation of Fn enables you to do exactly that. Let's build a simple custom function container image to see how it's done.
As you make your way through this tutorial, look out for this icon. Whenever you see it, it's time for you to perform an action.
This tutorial requires you to have both Docker and Fn installed. If you need help with Fn installation you can find instructions in the Install and Start Fn Tutorial.
If it isn't already running, you'll need to start the Fn server. We'll run it in the foreground to let us see the server log messages so let's open a new terminal for this.
Start the Fn server using the fn
cli:
fn start
The Fn HotWrap tool allows you to create functions using conventional Unix command line tools and a Docker container. The tool provides the FDK contract for any command that can be run on the command line. Once wrapped, event data is passed to your function via STDIN and the output is returned through STDOUT.
To begin with, let's use the Linux rev
command. The command reverses text, so this command:
echo "Hello World" | rev
Produces:
dlroW olleH
So we only need to call the command /bin/rev
for our function.
Next we need a directory for our project.
Create a folder named revfunc. Change into the folder.
In the folder , create a
func.yaml
file and copy/paste the following as its content:
schema_version: 20180708
name: revfunc
version: 0.0.1
runtime: docker
triggers:
- name: revfunc
type: http
source: /revfunc
This is a typical func.yaml
except that instead of declaring the runtime
as a programming language we've specified "docker". If you were to type fn build
right now you'd get the error:
Fn: Dockerfile does not exist for 'docker' runtime
This is because when you set the runtime type to "docker". The fn build
command defers to your Dockerfile to build the function container image--and you
haven't defined one yet!
Now you need to create a Dockerfile
.
Create a file named
Dockerfile
and copy/paste the following as its content:
FROM alpine:latest
# Install hotwrap binary in your container
COPY --from=fnproject/hotwrap:latest /hotwrap /hotwrap
CMD "/bin/rev"
ENTRYPOINT ["/hotwrap"]
Here is an explanation of each of the Docker commands.
FROM alpine:latest
- Use the latest version of Alpine Linux as the base image.COPY --from=fnproject/hotwrap:latest /hotwrap /hotwrap
- Install the HotWrap Fn tool.CMD "/bin/rev"
- The Linux command to run.ENTRYPOINT ["/hotwrap"]
- Tells the container to execute the previous command using HotWrap:/hotwrap /bin/rev
Once you have your custom Dockerfile you can simply use fn build
to build
your function. Give it a try:
fn -v build
You should see output similar to:
Building image fndemouser/revfunc:0.0.1
FN_REGISTRY: fndemouser
Current Context: default
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM alpine:latest
latest: Pulling from library/alpine
9d48c3bd43c5: Pull complete
Digest: sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb
Status: Downloaded newer image for alpine:latest
---> 961769676411
Step 2/4 : COPY --from=fnproject/hotwrap:latest /hotwrap /hotwrap
latest: Pulling from fnproject/hotwrap
e6b890787691: Pull complete
Digest: sha256:bf6303d7d216581c0e760f33dd74c3cdea83edad69f3d9614b7f573ba62c22b4
Status: Downloaded newer image for fnproject/hotwrap:latest
---> b999e7d793ff
Step 3/4 : CMD "/bin/rev"
---> Running in b60971040cd0
Removing intermediate container b60971040cd0
---> 5fa7a768081c
Step 4/4 : ENTRYPOINT ["/hotwrap"]
---> Running in 693c2d86cb7e
Removing intermediate container 693c2d86cb7e
---> 34d833b6acc2
Successfully built 34d833b6acc2
Successfully tagged fndemouser/revfunc:0.0.1
Just like with a default build, the output is a container image. From this point forward everything is just as it would be for any Fn function. Since you've previously started an Fn server, you can deploy it. First, create an application named 'revapp'.
Create an application:
fn create app revapp
Next, deploy your function to that app.
Deploy the function to the application:
fn deploy --app revapp --local --no-bump
We can confirm the function is correctly defined by getting a list of the functions in the "revapp" application:
fn list functions revapp
You should get output similar to:
NAME IMAGE ID
revfunc fndemouser/revfunc:0.0.1 01DQ8R97QTNG8G00GZJ0000002
Pro tip: The Fn cli let's you abbreviate most of the keywords so you can
also say fn ls f revapp
! You should see the same output.
With the function deployed let's invoke it to make sure it's working as expected.
echo "Hello World" | fn invoke revapp rev-func
For this command you should see the following output:
dlroW olleH
We included an HTTP trigger declaration in the func.yaml
so we can also call
the function with curl
:
curl --data "Hello World" -H "Content-Type: text/plain" -X POST http://localhost:8080/t/revapp/revfunc
You should get exactly the same output as when using fn invoke
.
dlroW olleH
One of the most powerful features of Fn is the ability to use custom defined Docker container images as functions. This feature makes it possible to customize your function's runtime environment including letting you use Linux command line tools as your function. And thanks to the Fn CLI's support for Dockerfiles it's the same user experience as when developing any function.
Having completed this tutorial you've successfully built a function using a custom Dockerfile. Congratulations!
Go: Back to Contents