Skip to content

Docker injection images

Some utilities that Whitebox requires to operate need to be built from source (for example, ffmpeg). As those images seldom update, we can build them once and reuse that build in all future builds.

As an example, take a look at packaging/docker/injection_images/ffmpeg.Dockerfile. It downloads ffmpeg and compiles it with flags that we need, allowing us to reuse this image. For easier access, this image is distributed to Whitebox project's container registry.

Using injection images

To use an injection image, you should find it at the container repository, and you can then copy its files inside the container you are building. For example, with ffmpeg, everything that's compiled resides in /usr/local/, so to use it, you need to COPY all those files into your build:

COPY --from=IMAGE_LOCATION /usr/local/ /usr/local/

Some injection images may need additional steps, such as dynamic linked update, additional dependency installations through package manager, etc. Refer to the originating Dockerfile's comments, in this example - ffmpeg.Dockerfile.

Building and managing injection images

To simplify image management, there is a packaging/scripts/maintenance/build_registry_images.sh script available. You can use it to build (and push) *.Dockerfiles inside packaging/docker/injection_images/ and packaging/docker/standalone_images/.

You can either specify image names, or provide --all argument to specify build targets. Additionally, provide --push to push them to registry.

Tag version, obtained from Dockerfile's ENV REGISTRY_TAG=VERSION_VALUE line, will be used to tag the resulting image and will be pushed with that tag. If the file does not contain such a line, image will not be built.

Writing Dockerfiles for injection images

File contents

As mentioned above, these Dockerfiles need to be placed within packaging/docker/injection_images/.

The script needs to define environment variable REGISTRY_TAG that will be used to infer the tag version when pushing the image. For example, if you want your image to be tagged with version 1.3.37a, you would need to place this line in your file:

ENV REGISTRY_TAG=1.3.37a

Optimizing image size

When writing an image to compile a program, the resulting image is usually going to be extremely heavy, as it would contain minimal OS layer, compilers, additionally downloaded dependencies, etc. As these images exist only to hold data to be injected into other images, you can strip the end result image to contain only the data they actually need to provide (e.g. produced libraries and executables). Even if not technically mandatory, you should not skip this step as the gains can be huge (e.g. for ffmpeg, this reduced the resulting image size from ~750MB to ~75MB).

For the sake of the example, let's assume:

  • Your build requires you to start from debian image
  • Your build's output is contained to two dirs, /usr/local/and/opt/helloworld/`

You can start a new image from a blank slate and just add those files to it:

# Name the first build step for easier access
FROM debian AS builder
ENV ENV REGISTRY_TAG=1.3.37a
# Run your build here that produces those files

# Now let's create a new build step, that will be the actual end resulting image
# that gets pushed to the registry
FROM scratch
COPY --from=builder /usr/local/ /usr/local/
COPY --from=builder /opt/helloworld/ /opt/helloworld/

And voilĂ ~, you now have a lightweight image!