Factory
A layer cache for image builds, and the canary that caught its first release
· Toolkit · 2 min read
GitLab's shared runners start every job with an empty Docker. An image build from the delivery kit therefore restored its NuGet packages and compiled the API from nothing on every run, including runs where no backend file had changed.
The cache lives in the registry
Delivery kit 1.4.0, released on 20 October 2026, gives the image-build component an input cache with two values: none, the default, and registry. With registry the build runs with buildx on the docker-container driver and reads its layers from <image>:buildcache in the project's container registry. Only the default branch writes them back. A merge request build reads the cache and pushes nothing, so it cannot replace the layers that main relies on. A product that does not set the input sees no change.
The cache asks one thing of a Dockerfile: restored packages must stay in an image layer. A RUN --mount=type=cache directory is never exported to the registry, so a restore layer taken from the cache would leave the next step without its packages. Probe, the product we keep to take every kit release first, dropped its NuGet cache mounts for that reason.
Caught on a real runner
Version 1.4.0 passed its tests on a workstation and failed on Probe's first build five minutes after release. The kit's jobs talk to Docker over TLS, and docker buildx create refuses TLS settings taken from the environment. No other product had pinned it. Version 1.4.1, released 14 minutes after 1.4.0, creates the builder on a Docker context made from the same settings.
Until then the kit's own pipeline checked that image-build renders, but never ran its script. A new job, delivery:image-build-test, runs that script on a TLS Docker-in-Docker, as in a product's pipeline, against a registry started inside it. It checks that the default branch writes the cache, that a new builder reads it, that another branch reads it and pushes nothing, and that a build without a cache still works. Against the 1.4.0 template it fails 7 of its 10 checks.
On Probe's main, the first build of the API image took 91 seconds and wrote the cache. A rerun of the same commit, the best case, took 33 seconds, with the restore and publish steps served from the registry. In Probe's Dockerfile the restore layer depends only on the project and build settings files, so a commit that changes only code should still reuse it.
To use it, pin 1.4.1, set cache: registry on the images with a slow restore, keep the buildcache tag out of the registry's cleanup policy, and remove package cache mounts from the Dockerfile first.