You're a service provider with custom functionality or functions
If you offer a way for customers to provide you custom code, you can invoke the Function Builder API to create a container image, which you can then deploy via the OpenFaaS REST API.
This means you can extend your platform for customers with a few simple steps.
You manage dozens or hundreds of functions
Instead of defining hundreds of different CI jobs or definitions in Jenkins, GitHub Actions, or GitLab, you can integrate with the Builder's REST API to build functions programmatically.
That means you have less to maintain and keep up to date, particularly if you need to make a change across your functions later down the line or if you want to apply policies and governance.
You're already building images in-cluster
If you're sharing a Docker socket from the host into your cluster, or running a container with Docker in Docker (DIND), or in privileged mode, this is making your cluster vulnerable to serious attacks.
The Function Builder API builds images in-cluster, but can run without root privileges, or needing to run Docker.
You are using GovCloud
If you're using GovCloud, then your auditer or compliance partner may have already told you that your product should not have external dependencies on separate build systems. The Function Builder API can be run rootless, without privileges and without needing to share a Docker socket.
The Function Builder uses Buildkit, developed by the Docker community to perform fast, cached, in-cluster builds via a HTTP API and uses mTLS for encryption.
You can use various self-hosted, open-source and managed cloud container registries with the Function Builder API.
We provide the following examples to help you explore and get started:
Remote builds via faas-cli for testing purposes
Step by step commands with curl and bash to show you how the workflow works
Code examples in various languages to show you how to integrate for production
Note
Authentication is required to publish images to remote registries. You must make sure that you do not include a configuration file from your machine directly, if the credentials keystore is enabled in Docker Desktop. See the helm chart for more details.
The faas-clipublish and up commands can use the --remote-builder flag to perform remote builds with the Function Builder. The path to the file containing the payload secret should be specified through the --payload-secret flag.
First, port-forward the builder, and obtain the payload secret:
As an alternative to a private or authenticated registry, you can use ttl.sh by Replicated as a temporary registry for testing (only). It allows you to publish containers that are removed after a certain time-limit, try ttl.sh/test-image-hello:1h for an image that is removed after 1 hour.
You can use any registry that is configured in your config.json file by changing the image field in the configuration file.
Create a build context using the faas-cli build --shrinkwrap command:
# Prepare a temporary directory
rm-rf/tmp/functions
mkdir-p/tmp/functions
cd/tmp/functions
# Create a new function
faas-clinew--langnode22hello-world
# The shrinkwrap command performs the templating # stage, then stops before running "docker build"# Look in ./build/hello-world to see the contents # that is normally passed to "docker build"
faas-clibuild--shrinkwrap-fstack.yaml
# Now rename "hello-world" to "context"# since that's the folder name expected by the buildercdbuild
rm-rfcontext
mvhello-worldcontext
# Create a config file with the registry and the # image name that you want to use for publishing the # function.exportREGISTRY=ttl.sh
exportOWNER=alexellis2
echo-n'{"image": "'$REGISTRY'/'$OWNER'/test-image-hello:0.1.0", "platforms": ["linux/amd64"]}'>com.openfaas.docker.config
Note: The platforms key is optional and is only used to specify the platform of the image to build. If not specified, the builder will build an image for the host platform, for multi-arch builds you could set the value to i.e. ["linux/amd64","linux/arm64"].
If you wish, you can also construct this filesystem using your own application, but it is easier to execute the faas-cli command from your own code.
Then create a tar archive of the context of the /tmp/functions/build/ directory:
{"log":["2021-10-20T16:48:34Z [ship 1/16] WORKDIR /home/app/","2021-10-20T16:48:34Z exporting to image 8.01s"],"image":"ttl.sh/alexellis2/test-image-hello:0.1.0","status":"success"}
The initial build is likely to take some time, however, if you run the build again or only change some text within a file the subsequent build could complete with single-digit seconds.
If you receive an error, try removing |jq and add -v to the curl command.
Construct a folder called context with the files needed to build a container
faas-cli build --shrinkwrap can help here, and allow you to use the existing templates we provide, or one of your own.
Any valid folder with a Dockerfile will work.
Create a configuration file
The configuration file should be called com.openfaas.docker.config and be placed outside of the context folder (see the example above with curl)
Create a tar file
Create a tar file which contains com.openfaas.docker.config and context/*.
Calculate the HMAC of the tar file
Calculate the HMAC of the tar file using a standard crypto library, you'll also need to input the payload secret for the function builder.
Invoke the API via HTTP
Next, invoke the API's /build endpoint.
You'll receive a JSON result with the status, logs and an image name if the image was published successfully.
{"log":["2022-06-23T09:10:12Z [ship 15/16] RUN npm test 0.35s","2022-06-23T09:10:13Z [ship 16/16] WORKDIR /home/app/","2022-06-23T09:10:13Z [ship 16/16] WORKDIR /home/app/ 0.09s","2022-06-23T09:10:13Z exporting to image","2022-06-23T09:11:06Z pushing manifest for ttl.sh/openfaas-image:1h@sha256:b077f553245c09d789980d081d33d46b93a23c24a5ec0a9c3c26be2c768db93e 0","2022-06-23T09:11:09Z pushing manifest for ttl.sh/openfaas-image:1h@sha256:b077f553245c09d789980d081d33d46b93a23c24a5ec0a9c3c26be2c768db93e 0","2022-06-23T09:10:13Z exporting to image 5.18s"],"image":"ttl.sh/openfaas-image:1h","status":"success","duration":0.843}
The duration field is given in seconds and is the total time taken to build the image including pulling base layers, exporting the image, and pushing it to the registry.
You should be able to translate the example given with curl into any programming language, but if you need additional support, feel free to reach out to us.
How to stream the logs and status output from a build¶
Note: this feature requires a version later than 0.4.3.
By default, the builder will prepare all logs and statuses in memory, and to send them after the build is completed.
If you would like to display live feedback to your users, you can set a HTTP Accept header of application/x-ndjson and the builder will stream the logs and status output as they are generated.
When the build fails, further details may be included in the error field.
{"image":"ttl.sh/alexellis2/test-image-hello:0.1.0","status":"failure","error":"failed to solve: process \"/bin/sh -c npm i\" did not complete successfully: exit code: 1","duration":0.843}
You may wish to cross-compile a function to run on an arm64 host, if so, you can provide a platform key in the configuration file.
When no platforms key is specified, the builder will build an image for the host platform.
You will need to make sure your Dockerfile uses the proper syntax, the official templates are a good reference if you need guidance, otherwise reach out to our team if you get stuck.
The below will build an image for arm64 only and must be deployed only to an arm64 host using OpenFaaS Profiles to ensure it is scheduled correctly to an arm64 host.
multi-arch images will usually take longer to publish than single-arch images due to emulation with QEMU
any steps performed under a TARGETARCH which differs from BUILDARCH will be emulated with QEMU which will add overhead to the build process - you can mitigate this by running a dedicated arm64 and amd64 pro-builder Helm chart installation
You can skip pushing the image to the registry by setting the skipPush key to true in the configuration file.
{"skipPush":true}
In this mode, the builder can be configured through additional parameters to build directly into the containerd library for instant deployment to OpenFaaS Edge. Contact us for more information if this use-case is of interest to you.
You can limit the amount of concurrent requests that a builder will accept by setting proBuilder.maxInflight: N within the helm chart or the max_inflight environment variable on the Deployment.
We would encourage you to review the RAM and CPU limits that you've set for your builder, and to experiment with what kind of value to use for max_inflight. You could start with a high number, and reduce it over time, until it's too low to get the kind of results you need.
Your total build capacity will be: max_inflight * pro-builder replicas, so if you have 2 replicas and max_inflight is 3, then you can build 6 functions at once.
Once in place, a busy worker will return responses like this:
The pro-builder will be marked as unready by Kubernetes, and if you have other replicas (see above section), then when you retry the request, it should hit a ready worker instead.
Why not use a function to invoke the API?
If you do not have code to retry invocations in your own product/system, OpenFaaS Pro supports this through its async queue-worker, and you could use a function in a separate namespace like openfaas-system to queue builds more reliably during busy periods. Feel free to reach out to us if you have questions about this approach.