Skip to content

Docker Runner

Copy page

This page records the Docker Runner checked on 2026-10-17. Reference example output is produced in this Debian Bookworm container. The repository is not public yet, so the container definition is included below.

The container copies Go, Node.js, Elixir, and Erlang/OTP from official language images, and uses the matching Python image as its base. libvips is compiled from the upstream source tarball at a pinned version and checksum. The container uses that in-image library rather than the distribution package.

For the version comparison table, see the version compatibility matrix. On your own machine, trust the versions printed by install and verify.

Role Component Version Notes
Container Go 1.27.0 From golang:1.27.0-bookworm
Container Node.js 24.14.1 Copied from the official Node image for sharp
Container pnpm 12.11.2 Activated through Corepack
Container Python 3.14.5 Base image python:3.14.5-bookworm
Container Elixir / OTP 1.20.4 / 29.1.2 From hexpm/elixir:1.20.4-erlang-29.1.2-debian-bookworm-20261005
Container libvips 8.17.3 Built from source in the container and installed to /usr/local
Reference govips v2.20.0 Linked to libvips 8.17.3 above
Comparison pyvips 3.2.0 Linked to the same libvips 8.17.3
Comparison vips CLI 8.17.3 Shares that library with the reference
Comparison sharp 0.35.5 Uses libvips 8.18.7 bundled in the npm package
Comparison Image / Vix 0.72.0 / 0.42.0 Linked to the same libvips 8.17.3; covers a subset of examples
  1. The container supplies the compilers and language runtimes in the table, plus libvips 8.17.3 built from source.
  2. Go/govips is the reference implementation. It links that libvips, runs the operation on one shared input, and writes the image together with metadata such as version and dimensions.
  3. sharp, pyvips, and the vips CLI each run the same processing intent. Elixir Image links the same libvips through Vix, with VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS at compile time and at runtime. Image currently covers the thumbnail, format conversion, geometry, alpha, and colour examples. Those runs stay an extra comparison entry, recorded separately from the govips reference.
  4. Each output records format, dimensions, bands, and byte size. Matching byte size means the files are the same length. Whether the pixels match stays a separate, later conclusion.
  5. Those outputs stay with their format, dimensions, and version metadata for later comparison.

The image’s default command only prints the pnpm version. An example run replaces that command with the command for the interface being executed. The image sets VIPS_RUNNER=1 to mark that the process is inside this example environment. The variable does not change how libvips loads files.

  • Go, Node.js, Elixir, and OTP are copied into the final image from the official images above, so one base image does not have to install four language toolchains itself.
  • The Node.js image contributes node and the npm modules. Corepack activates pnpm 12.11.2.
  • libsctp1 keeps OTP from warning about a missing SCTP library at startup.
  • pyvips 3.2.0 is installed at the end of the image build, and the build asserts that it loads libvips 8.17.3.
  • Elixir and OTP stay in the image. Image and Vix are compiled when an example needs them, and they link the libvips inside the image rather than the prebuilt library Vix bundles by default. The image does not install FFmpeg, Nx, evision, or image_vision.
  • The image leaves VIPS_BLOCK_UNTRUSTED unset. Image sets that switch itself when the application starts. A global environment value would also change how govips, pyvips, and the CLI load files.
  • Text examples use the installed DejaVu Sans, and the image build refreshes the font cache before it finishes.

libvips is installed under /usr/local as a release build, with dynamic modules disabled. The build checks that the JPEG, WebP, PNG, SVG, and HEIF loaders appear in the output of vips -l foreign.

Capabilities used by the current examples stay enabled: JPEG, PNG, WebP, TIFF, SVG (librsvg), Pango/Cairo text, fontconfig, HEIF, cgif, libspng, OpenJPEG, libimagequant, libarchive, libexif, lcms2, and fftw3. HEIF stays enabled, without a dynamic module. A missing AVIF/HEIF loader then shows up in the loader list, instead of failing only on a later call.

These loaders are disabled: ImageMagick, OpenSlide, FITS, NIfTI, OpenEXR, Poppler, PDF, JPEG XL, plus quantizr and Highway. Current examples use JPEG, PNG, WebP, TIFF, and SVG. ImageMagick is disabled so a distribution Magick loader cannot insert itself ahead of the native JPEG, PNG, and WebP savers and change foreign-loader priority.

This is the example container definition as of 2026-10-17.

# Recipe runner for the VIPS Handbook.
# Versions come from toolchain.lock.yml. Node is pinned to 24.14.1, the patch
# already checked on the reference workstation; the lock file accepts any Node 24.
#
# Do not set VIPS_BLOCK_UNTRUSTED here. elixir-image/image sets it when that
# application starts, and a global setting would change govips, pyvips, and CLI loads.
FROM golang:1.27.0-bookworm AS go-toolchain
FROM node:24.14.1-bookworm AS node-toolchain
FROM hexpm/elixir:1.20.4-erlang-29.1.2-debian-bookworm-20261005 AS elixir-toolchain
FROM python:3.14.5-bookworm
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
VIPS_RUNNER=1 \
VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS \
GOCACHE=/tmp/vips-handbook-go-cache \
GOPROXY=https://proxy.golang.org,direct \
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig \
COREPACK_ENABLE_DOWNLOAD_PROMPT=0
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
cmake \
fontconfig \
fonts-dejavu-core \
git \
libarchive-dev \
libcairo2-dev \
libcgif-dev \
libexif-dev \
libexpat1-dev \
libfftw3-dev \
libfontconfig1-dev \
libglib2.0-dev \
libheif-dev \
libimagequant-dev \
libjpeg62-turbo-dev \
liblcms2-dev \
libopenjp2-7-dev \
libpango1.0-dev \
libpng-dev \
libsctp1 \
librsvg2-dev \
libspng-dev \
libtiff-dev \
libwebp-dev \
meson \
ninja-build \
pkg-config \
time \
xz-utils \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
COPY --from=go-toolchain /usr/local/go /usr/local/go
COPY --from=node-toolchain /usr/local/bin/node /usr/local/bin/node
COPY --from=node-toolchain /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -sfn ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -sfn ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx \
&& ln -sfn ../lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack \
&& corepack enable \
&& corepack prepare pnpm@12.11.2 --activate
COPY --from=elixir-toolchain /usr/local/lib/erlang /usr/local/lib/erlang
COPY --from=elixir-toolchain /usr/local/lib/elixir /usr/local/lib/elixir
RUN ln -sfn ../lib/erlang/bin/erl /usr/local/bin/erl \
&& ln -sfn ../lib/erlang/bin/erlc /usr/local/bin/erlc \
&& ln -sfn ../lib/erlang/bin/escript /usr/local/bin/escript \
&& ln -sfn ../lib/erlang/bin/epmd /usr/local/bin/epmd \
&& ln -sfn ../lib/elixir/bin/elixir /usr/local/bin/elixir \
&& ln -sfn ../lib/elixir/bin/elixirc /usr/local/bin/elixirc \
&& ln -sfn ../lib/elixir/bin/iex /usr/local/bin/iex \
&& ln -sfn ../lib/elixir/bin/mix /usr/local/bin/mix
# libvips 8.17.3 is built in-image so `vips --version` matches the lock file.
# ImageMagick, OpenSlide, FITS, NIfTI, and JPEG XL are left out: current recipes
# use JPEG, PNG, WebP, TIFF, and SVG, and a distro Magick loader would change
# foreign-loader priority. HEIF stays enabled so a missing AVIF/HEIF loader is
# visible in `vips -l foreign` rather than failing silently later.
ARG LIBVIPS_VERSION=8.17.3
ARG LIBVIPS_SHA256=41e9a1439cd57dcc6d4435a085e2cfe181d9da1962fa84a484f09e8b536e4b77
ADD --checksum=sha256:${LIBVIPS_SHA256} \
https://github.com/libvips/libvips/releases/download/v${LIBVIPS_VERSION}/vips-${LIBVIPS_VERSION}.tar.xz \
/tmp/vips.tar.xz
RUN tar -xJf /tmp/vips.tar.xz -C /tmp \
&& cd /tmp/vips-${LIBVIPS_VERSION} \
&& meson setup build \
--prefix=/usr/local \
--libdir=lib \
--buildtype=release \
-Ddeprecated=false \
-Dexamples=false \
-Dintrospection=disabled \
-Dmodules=disabled \
-Dmagick=disabled \
-Dmagick-module=disabled \
-Dcfitsio=disabled \
-Dmatio=disabled \
-Dnifti=disabled \
-Dopenexr=disabled \
-Dopenslide=disabled \
-Dopenslide-module=disabled \
-Dpdfium=disabled \
-Dpoppler=disabled \
-Dpoppler-module=disabled \
-Djpeg-xl=disabled \
-Djpeg-xl-module=disabled \
-Dquantizr=disabled \
-Dhighway=disabled \
-Djpeg=enabled \
-Dpng=enabled \
-Dwebp=enabled \
-Dtiff=enabled \
-Dexif=enabled \
-Dlcms=enabled \
-Dfftw=enabled \
-Dfontconfig=enabled \
-Dpangocairo=enabled \
-Drsvg=enabled \
-Dheif=enabled \
-Dheif-module=disabled \
-Dcgif=enabled \
-Dspng=enabled \
-Dopenjpeg=enabled \
-Dimagequant=enabled \
-Darchive=enabled \
-Dzlib=enabled \
-Dnsgif=true \
&& meson compile -C build \
&& meson install -C build \
&& echo /usr/local/lib > /etc/ld.so.conf.d/usr-local.conf \
&& ldconfig \
&& fc-cache -f \
&& mkdir -p /opt/vips-handbook \
&& vips -l foreign > /opt/vips-handbook/foreign-loaders.txt \
&& grep -q 'jpegload' /opt/vips-handbook/foreign-loaders.txt \
&& grep -q 'webpload' /opt/vips-handbook/foreign-loaders.txt \
&& grep -q 'pngload' /opt/vips-handbook/foreign-loaders.txt \
&& grep -q 'svgload' /opt/vips-handbook/foreign-loaders.txt \
&& grep -q 'heifload' /opt/vips-handbook/foreign-loaders.txt \
&& rm -rf /tmp/vips-${LIBVIPS_VERSION} /tmp/vips.tar.xz
RUN pip install --no-cache-dir 'pyvips==3.2.0' \
&& python3 -c "import pyvips; v='.'.join(str(pyvips.version(i)) for i in range(3)); assert pyvips.__version__=='3.2.0', pyvips.__version__; assert v=='8.17.3', v" \
&& test "${VIX_COMPILATION_MODE}" = "PLATFORM_PROVIDED_LIBVIPS" \
&& test -z "${VIPS_BLOCK_UNTRUSTED:-}" \
&& vips --version | grep -qx 'vips-8.17.3'
WORKDIR /work
CMD ["pnpm", "--version"]