BuildKit mounts
Mount a cache, secret, or build-context path for the duration of a with block. Every RUN inside the block picks up the open mounts, and nothing leaks past it.
Scope mounts to a block
This recipe installs dependencies with a pip cache and a bind-mounted context, then adds private packages behind a secret:
from __future__ import annotations
from docker_dsl import Stage
from docker_dsl import context as ctx
ctx.register("private", bool)
with Stage("python:3.13-slim") as s:
s.workdir("/app")
with s.bind(source=".", target="/app"), s.cache("/root/.cache/pip"), s.run() as r:
r.pip("install", "--requirement", "requirements.txt")
if ctx.private:
with s.secret("pypi", target="/root/.netrc"), s.cache("/root/.cache/pip"), s.run() as r:
r.pip("install", "--requirement", "requirements-private.txt")Render it with --private=true:
# syntax=docker/dockerfile:1
FROM python:3.13-slim AS base
WORKDIR /app
RUN --mount=type=bind,source=.,target=/app --mount=type=cache,target=/root/.cache/pip,sharing=shared \
pip install --requirement requirements.txt
RUN --mount=type=secret,id=pypi,target=/root/.netrc --mount=type=cache,target=/root/.cache/pip,sharing=shared \
pip install --requirement requirements-private.txtThe three mount types
s.cache(target, lock=False)mounts a persistent cache that survives between builds. Passlock=Trueforsharing=lockedwhen concurrent builds write the same cache.s.secret(id, target=...)mounts a secret supplied at build time withdocker build --secret id=<id>,.... It never lands in an image layer.s.bind(source=..., target=...)mounts a build-context path read-only, for files a command needs without aCOPY.
Combining and nesting
List several scopes in one with to apply them together, and add s.run() last to open the builder under all of them:
with s.cache("/root/.cache/pip"), s.secret("pypi", target="/root/.netrc"), s.run() as r:
r.pip("install", "--requirement", "requirements.txt")The mounts apply only to commands inside the block. A RUN outside it carries none of them.