ADR 0005: Docker image strategy
- Status: accepted
- Date: 2026-09-26
Context
Section titled “Context”Users deploy on Dokploy, Coolify and Kubernetes and expect docker run with no build step. No existing base image fits: imgproxy’s base lacks LibRaw, PDF, magick, OpenJPEG, libspng, libultrahdr and jemalloc; imagor’s includes GPL x265 and poppler.
Decision
Section titled “Decision”-
Own base image built from a fork of imgproxy-docker-base scripts (MIT, attributed), adding libspng, OpenJPEG, libultrahdr and jemalloc in M1, and LibRaw 0.22.x, PDFium prebuilt binaries, OpenEXR and restricted ImageMagick 7 (PSD only) in M2, all under
/opt/xtandard. Pinned versions with checksums, weekly rebuilds, published asghcr.io/xantiagoma/xtandard-image-base:<vips>-r<N>-<flavor>. -
Three flavors and tags (the third added 2026-09-27, ADR 0006 amendment):
Flavor Contents Licence label Base tags Stages slimall still formats MIT<vips>-r<N>-slim[-builder],slim[-builder]builder,runtimefullslim + FFmpeg 8 LGPL (VP8/VP9/AV1 encode, no H.264/HEVC encode) + ONNX Runtime with permissive models MIT<vips>-r<M>-full[-builder],full[-builder]builder-full,runtime-fullgplfull + FFmpeg rebuilt with --enable-gpl+ x264 (H.264 encode) + x265 (HEVC encode) + Ghostscriptgsfor EPS input (WP-99, ADR 0011, off by default); contains GPL and AGPL softwareAGPL-3.0-or-later AND GPL-2.0-or-later AND MIT<vips>-r<G>-gpl[-builder],gpl[-builder]builder-gpl,runtime-gplEach flavor builds on the previous one’s finished dependency stage (
deps→full-deps→gpl-deps) with its own pins file (versions.sh,versions-full.sh,versions-gpl.sh) and revision counter, so a change to a later flavor never rebuilds or changes an earlier one.slimstays the default. -
App image is multi-stage: build with the base image, run on
ubuntu:noblewith only the runtime libraries copied;LD_PRELOADjemalloc; UID 65532;HEALTHCHECKvia the binary’shealthsubcommand; ports 8080 (HTTP) and 9090 (metrics). -
Multi-arch amd64 + arm64 on native runners, cosign signatures, SBOM, license bundle in
/opt/xtandard/share/licenses. -
CI integration tests run against the exact published image, started with
docker compose(go-standards §8).
Consequences
Section titled “Consequences”- We own a C dependency build: security updates are our responsibility (Renovate on
versions.sh, weekly rebuilds). - glibc runtime (not distroless-static/musl) because PDFium and ONNX Runtime ship glibc binaries.
fullis materially larger (target ≤ 170 MB compressed vs ≤ 110 MB slim).- WP-66 (base revision
r2) added the M2 extras to slim: LibRaw 0.22.x (LGPL-2.1, https://www.libraw.org/), PDFium prebuilt from https://github.com/bblanchon/pdfium-binaries (BSD-3-Clause; poppler stays out), OpenEXR 3.4.x + Imath 3.2.x (BSD-3-Clause, https://openexr.com/), and ImageMagick 7 (ImageMagick License, https://imagemagick.org/license/) as MagickCore only, loaded by libvips through the singlevips-magick.somodule and restricted to reading PSD/PSB bydocker/base/magick-policy.xml. Licence details in ADR 0006; sizes indocker/base/README.md. - WP-70 (full flavor, revision
r3) adds thebuilder-fullandruntime-fulltargets on top of the slim stages (the full build starts from the finished slimdepsstage): FFmpeg 8.1 LGPL-only (video demux/decode, VP8/VP9 via libvpx and AV1 via the slim libaom/dav1d, no H.264/HEVC encode, no audio), the prebuilt ONNX Runtime 1.30 CPU library in/usr/local/lib, and the YuNet (MIT) and YOLOX-s (Apache-2.0) ONNX models in/usr/share/xtandard/models. Its pins live indocker/base/versions-full.shso slim never changes when they move; the full tag carries its own revision (XI_BASE_FULL_REVISION). Built locally for the host architecture withtask docker:base:full; the multi-arch publishing path is described in.github/workflows/base-image.yml(disabled while Actions is off). - WP-70b (gpl flavor, revision
r3) adds thebuilder-gplandruntime-gpltargets on top offull-deps: x264 (stable branch, build 165) and x265 4.2 as shared libraries, and FFmpeg rebuilt with exactly the full configuration plus--enable-gpl --enable-libx264 --enable-libx265. It is opt-in and GPL-licensed as a whole (ADR 0006 amendment 2026-09-27);/opt/xtandard/share/licenses/LICENSE-GPL.mdstates the terms and the patent caveat. Built locally withtask docker:base:gpl; the workflow matrix includes it.