Docker Runner
本页记录 2026-10-17 核过的 Docker Runner。示例的参考结果在这个 Debian Bookworm 容器里生成。仓库尚未公开,因此容器定义直接写在下面。
容器从官方语言镜像带入 Go、Node.js、Elixir 与 Erlang/OTP,基底是对应版本的 Python 镜像。libvips 按固定版本和校验和从上游源码包编译安装,使用的是这份容器内的库,而不是发行版软件包里的 libvips。
版本数字的对照表见版本兼容矩阵。在自己的机器上安装时,仍以安装与环境检查里实际打印出的版本为准。
| 角色 | 组件 | 版本 | 说明 |
|---|---|---|---|
| 容器 | Go | 1.27.0 | 来自 golang:1.27.0-bookworm |
| 容器 | Node.js | 24.14.1 | 随官方 Node 镜像复制进来,供 sharp 使用 |
| 容器 | pnpm | 12.11.2 | 由 Corepack 启用 |
| 容器 | Python | 3.14.5 | 容器基底 python:3.14.5-bookworm |
| 容器 | Elixir / OTP | 1.20.4 / 29.1.2 | 来自 hexpm/elixir:1.20.4-erlang-29.1.2-debian-bookworm-20261005 |
| 容器 | libvips | 8.17.3 | 容器内源码构建,安装到 /usr/local |
| 参考 | govips | v2.20.0 | 链接上面的 libvips 8.17.3 |
| 比较 | pyvips | 3.2.0 | 链接同一份 libvips 8.17.3 |
| 比较 | vips CLI | 8.17.3 | 与参考实现共用这份库 |
| 比较 | sharp | 0.35.5 | 使用 npm 包自带的 libvips 8.18.7 |
| 比较 | Image / Vix | 0.72.0 / 0.42.0 | 链接同一份 libvips 8.17.3;只覆盖部分示例 |
一次示例如何跑完
Section titled “一次示例如何跑完”- 容器提供上表里的编译器、语言运行时,以及一份源码安装的 libvips 8.17.3。
- Go/govips 作为参考实现,链接这份 libvips,对同一张输入执行处理,并写出图像和版本、尺寸等元数据。
- sharp、pyvips 和 vips CLI 按同一处理意图各自执行。Elixir 的 Image 通过 Vix 链接同一份 libvips,编译和运行都使用
VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS。Image 目前只覆盖缩略图、格式转换、几何、Alpha 和色彩调节,它不是与前四个入口并列的参考实现。 - 每个输出记录格式、尺寸、通道和字节大小。相同字节数仍只说明文件大小相同。像素是否一致,留在后续比较里单独结论。
- 这些输出会带着格式、尺寸和版本信息一起留下,供后续对照。
镜像的默认命令只打印 pnpm 版本。真正跑示例时会换成对应入口的命令。镜像设置 VIPS_RUNNER=1,用来标明进程处在这份示例环境中;这个变量不改变 libvips 的加载行为。
- Go、Node.js、Elixir 与 OTP 从上面的官方镜像复制进最终镜像,避免在一份基底里分别安装四套语言工具链。
- Node.js 镜像只提供
node与 npm 模块。pnpm 12.11.2 由 Corepack 激活。 libsctp1让 OTP 启动时不必为缺少 SCTP 库发出警告。- pyvips 3.2.0 在镜像构建结束时安装,并断言它加载的是 libvips 8.17.3。
- Elixir 与 OTP 留在镜像里。Image 与 Vix 在运行对应示例时编译,并链接镜像内的 libvips,而不是 Vix 默认附带的预编译库。镜像不安装 FFmpeg、Nx、evision 或 image_vision。
- 镜像不设置
VIPS_BLOCK_UNTRUSTED。Image 会在应用启动时自行设置它;若把它写成全局环境变量,govips、pyvips 和 CLI 的加载行为也会一起改变。 - 文字示例使用已安装的 DejaVu Sans,并在构建结束时刷新字体缓存。
libvips 以 release 构建安装到 /usr/local,动态模块关闭。构建结束时会检查 JPEG、WebP、PNG、SVG 和 HEIF 加载器确实出现在 vips -l foreign 的输出里。
当前示例用到的能力保持启用:JPEG、PNG、WebP、TIFF、SVG(librsvg)、Pango/Cairo 文字、fontconfig、HEIF、cgif、libspng、OpenJPEG、libimagequant、libarchive、libexif、lcms2 和 fftw3。HEIF 保持启用,但不用动态模块。这样若 AVIF/HEIF 加载器缺失,会在加载器列表里直接看见,而不是拖到以后某次调用才失败。
以下加载器关闭:ImageMagick、OpenSlide、FITS、NIfTI、OpenEXR、Poppler、PDF、JPEG XL,以及 quantizr 与 Highway。当前示例使用 JPEG、PNG、WebP、TIFF 和 SVG。关掉 ImageMagick,是为了避免发行版里的 Magick 加载器插到原生 JPEG、PNG、WebP 保存器前面,改变外来加载器的优先级。
Dockerfile
Section titled “Dockerfile”下面是 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-toolchainFROM node:24.14.1-bookworm AS node-toolchainFROM 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/nodeCOPY --from=node-toolchain /usr/local/lib/node_modules /usr/local/lib/node_modulesRUN 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/erlangCOPY --from=elixir-toolchain /usr/local/lib/elixir /usr/local/lib/elixirRUN 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.3ARG LIBVIPS_SHA256=41e9a1439cd57dcc6d4435a085e2cfe181d9da1962fa84a484f09e8b536e4b77ADD --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 /workCMD ["pnpm", "--version"]- 安装与环境检查
- 版本兼容矩阵
- libvips 8.17.3 发布包,复核日期 2026-10-17