Topic 10.1
BuildKit & buildx: Multi-Arch, Cache Mounts & Build Secrets
In one line
BuildKit is Docker's modern build engine: parallel stages, cache mounts that keep dependency caches between builds, secret mounts that never land in layers, and buildx for multi-architecture images and shared remote caches in CI.
Think of it like this
A bakery upgrading from one baker to a production kitchen. Independent steps happen in parallel (stages), the flour store is kept between batches instead of being thrown away (cache mounts), the recipe's secret ingredient is brought in for mixing and never printed on the label (secret mounts), and the same recipe bakes for two different ovens (multi-arch).
Key ideas
- 01
BuildKit is the default builder in current Docker. It builds independent stages in parallel and skips stages the final target doesn't need. Enable features with the syntax line
# syntax=docker/dockerfile:1. - 02
CACHE MOUNTS:
RUN --mount=type=cache,target=/root/.m2 mvn -B packagekeeps Maven's local repository between builds without putting it in the image, so dependencies download once even whenpom.xmlchanges. The same works for npm (/root/.npm), pip, Go, and apt. - 03
SECRET MOUNTS:
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm cimakes a secret available during that one step only; it never appears in any layer or indocker history(unlike ARG/ENV, which leak: DevSecOps course, secret in image layer). Pass it withdocker build --secret id=npmrc,src=$HOME/.npmrc. SSH mounts (--mount=type=ssh) do the same for private Git dependencies. - 04
MULTI-ARCH with buildx:
docker buildx build --platform linux/amd64,linux/arm64 -t registry/app:1.4.0 --push .builds one image index with variants for Intel/AMD and ARM (Graviton servers, Apple Silicon laptops). Cross-builds use QEMU emulation (slow) or native builders per architecture (fast). - 05
REMOTE CACHE for CI: ephemeral CI runners lose the local cache every run.
--cache-to type=registry,ref=registry/app:buildcache,mode=maxand--cache-fromthe same ref share layer cache across runs and runners (ortype=ghaon GitHub Actions), often turning 8-minute builds into 1-minute builds (CI/CD course, caching).
In your stack
- →
For Maven, combine a cache mount on
/root/.m2with Spring Boot layered JARs (Phase 6): dependency resolution is cached by BuildKit, and the dependency layer is reused across releases, so only your classes change.
Code & diagrams
# syntax=docker/dockerfile:1
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /src
COPY pom.xml .
RUN --mount=type=cache,target=/root/.m2 mvn -B -q dependency:go-offline
COPY src ./src
RUN --mount=type=cache,target=/root/.m2 \
--mount=type=secret,id=maven_settings,target=/root/.m2/settings.xml \
mvn -B -q package -DskipTests
FROM eclipse-temurin:21-jre
RUN useradd -r -u 10001 app
COPY --from=build /src/target/app.jar /app/app.jar
USER 10001
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75", "-jar", "/app/app.jar"]docker buildx create --name ci --use
docker buildx build \
--platform linux/amd64,linux/arm64 \
--secret id=maven_settings,src=$HOME/.m2/settings.xml \
--cache-from type=registry,ref=ghcr.io/shoplite/api:buildcache \
--cache-to type=registry,ref=ghcr.io/shoplite/api:buildcache,mode=max \
-t ghcr.io/shoplite/api:sha-3f2a1c9 --push .
docker buildx imagetools inspect ghcr.io/shoplite/api:sha-3f2a1c9 # shows both platformsExplain it without notes
Why is passing a token with ARG unsafe, and how do secret mounts fix it?
What's the difference between the layer cache and a cache mount?
Practice
Your CI builds on amd64 but production moved to Graviton (arm64) and the container fails with 'exec format error'. Fix the pipeline.
Trade-offs
- ↔
Multi-arch builds widen where images run and enable cheaper ARM instances, at the cost of longer builds (emulation) or extra runners; remote caches speed CI but add registry storage.
Done when you can
I use cache mounts for dependency managers and secret mounts for credentials
I can build and inspect a multi-arch image with buildx and a remote cache