Build Contexts, .dockerignore, Remote Contexts, Named Contexts, and Deterministic Build Inputs: Guided Hands-On Workflow and Core Operations
Build and measure a small disposable project, minimize its default context, demonstrate Dockerfile-specific ignore behavior, introduce a named context, and capture plain BuildKit progress so the exact input boundary is visible rather than assumed.
Learning objectives
- Measure a disposable local context before and after excluding unnecessary files.
- Demonstrate Dockerfile-specific ignore-file precedence with a bounded, synthetic project.
- Use a named context to expose a second source tree without broadening the default context.
- Capture BuildKit plain progress and actual Engine/Buildx/BuildKit/frontend versions as evidence.
- Model a pinned Git source locally and show the current checksum-verification syntax as an optional network-capable path.
1. Lab scope: measure before optimizing
This lab creates a synthetic project with one application file, one documentation file, harmless noise, fake credential-shaped data, and generated output. The goal is to prove which files are in the default context and which are isolated in a named context. Nothing is pushed to a registry and no production source or credential is used.
2. Preflight: record the builder and feature baseline
mkdir -p ch08-lab/{app,docs,noise,evidence}
cd ch08-lab
docker context show | tee evidence/00-context.txt
docker version | tee evidence/01-version.txt
docker buildx version | tee evidence/02-buildx.txt
docker buildx inspect --bootstrap | tee evidence/03-builder.txt
If buildx inspect cannot bootstrap a disposable/local
builder, record that limitation and use the default builder. Do not
create a privileged shared builder merely to match the example.
3. Create synthetic inputs and a deliberately noisy repository
printf 'hello from bounded context\n' > app/message.txt
printf '# documentation\nonly through named context\n' > docs/readme.md
printf 'harmless-cache-%s\n' "$(date +%s)" > noise/large.tmp
printf 'FAKE_TOKEN=not-a-secret\n' > .env
mkdir -p .git-simulation dist node_modules
printf 'fake git metadata\n' > .git-simulation/HEAD
printf 'generated output\n' > dist/output.txt
printf 'dependency tree\n' > node_modules/dependency.txt
find . -maxdepth 2 -type f -print | sort | tee evidence/04-files-before.txt
du -sh . | tee evidence/05-directory-size.txt
The .env value is intentionally fake. It exists only to
demonstrate why credential-shaped files should never be present in
the build input unless explicitly needed through a safer mechanism.
4. Write a Dockerfile that consumes only the intended application input
# syntax=docker/dockerfile:1
FROM busybox:1.37.0
WORKDIR /app
COPY app/message.txt ./message.txt
CMD ["cat", "/app/message.txt"]
The Dockerfile references only one file, but without an ignore file the entire local context is still eligible for transfer/snapshotting. That difference is the central lesson.
5. Capture the unoptimized context evidence
docker buildx build --progress=plain --load \
--label devops-academy.lab=ch08-before \
-t devops-academy-ch08:before . 2>&1 | tee evidence/06-build-before.txt
docker image inspect devops-academy-ch08:before --format 'ImageID={{.Id}}' \
| tee evidence/07-image-before.txt
In the plain progress output, locate the step that transfers or loads the build context. Record the bytes shown by your builder. Different BuildKit versions/drivers format the line differently; preserve the actual output rather than inventing a number.
6. Minimize the default context explicitly
# .dockerignore
.env
.git
.git-simulation
node_modules
dist
noise
docs
evidence
*.log
docker buildx build --progress=plain --load \
--label devops-academy.lab=ch08-minimal \
-t devops-academy-ch08:minimal . 2>&1 | tee evidence/08-build-minimal.txt
docker image inspect devops-academy-ch08:minimal --format 'ImageID={{.Id}}' \
| tee evidence/09-image-minimal.txt
Compare the context-load lines from the two builds. The image payload should still contain the same application message, but the builder should no longer need the excluded trees.
7. Demonstrate Dockerfile-specific ignore precedence
# docs.Dockerfile
# syntax=docker/dockerfile:1
FROM busybox:1.37.0
WORKDIR /site
COPY docs/readme.md ./readme.md
CMD ["cat", "/site/readme.md"]
# docs.Dockerfile.dockerignore
.env
.git*
node_modules
dist
noise
evidence
app
docker buildx build --progress=plain --load \
-f docs.Dockerfile -t devops-academy-ch08:docs . \
2>&1 | tee evidence/10-docs-specific-ignore.txt
Because docs.Dockerfile.dockerignore is associated with
docs.Dockerfile, it governs that build instead of the
root ignore file. The root file excluded docs/; the
Dockerfile-specific file intentionally allows it.
8. Move documentation into an explicit named context
# named.Dockerfile
# syntax=docker/dockerfile:1
FROM busybox:1.37.0
WORKDIR /app
COPY app/message.txt ./message.txt
COPY --from=docs /readme.md ./docs/readme.md
CMD ["sh", "-c", "cat /app/message.txt; cat /app/docs/readme.md"]
docker buildx build --progress=plain --load \
-f named.Dockerfile \
--build-context docs=./docs \
-t devops-academy-ch08:named . \
2>&1 | tee evidence/11-named-context.txt
docker run --rm devops-academy-ch08:named | tee evidence/12-named-runtime.txt
The default context remains narrow while docs is
exposed as a separate source. Record both the default-context and
named-context lines from BuildKit progress.
9. Simulate a pinned Git source without requiring network access
git init source-repo
printf 'pinned source\n' > source-repo/source.txt
git -C source-repo add source.txt
git -C source-repo -c user.name='DevOps Academy' -c user.email='academy@example.invalid' commit -m 'lab source'
SRC_SHA=$(git -C source-repo rev-parse HEAD)
printf 'source_commit=%s\n' "$SRC_SHA" | tee evidence/13-local-git-source.txt
This local repository supplies immutable revision evidence without a
remote dependency. When network access and compatible
Buildx/Dockerfile versions are available, the equivalent remote
pattern is a Git URL query that combines a human-readable
tag/branch/ref with
checksum=$SRC_SHA.
10. Challenge: locate the ownership layer
A build run on a remote builder reports
COPY failed: file not found for
../shared/config.json. Decide whether to fix the
Dockerfile path, widen the default context, or add an explicit named
context. Explain why a client-relative path outside the context
cannot simply be assumed to exist on the builder.
11. Exact cleanup
docker image rm \
devops-academy-ch08:before \
devops-academy-ch08:minimal \
devops-academy-ch08:docs \
devops-academy-ch08:named
docker image ls --filter label=devops-academy.lab=ch08-before
docker image ls --filter label=devops-academy.lab=ch08-minimal
Do not use broad image/system prune. Preserve
evidence/ and the synthetic source files if you want to
compare them in the checkpoint.
Knowledge check
Why can a build transfer files that no
COPY instruction uses?
Because the context boundary is prepared independently from the later Dockerfile dependency graph. Ignore rules minimize what is available before build instructions consume it.
What evidence should you preserve when comparing context size?
The exact build command, ignore files, builder identity/version, and plain progress lines showing context loading/transfer.
Why is the local Git simulation still useful?
It teaches immutable revision identity without requiring network access or a public repository.
What does
--build-context docs=./docs change?
It supplies an additional context named docs; it
does not make docs/ part of the default context.
Why should the evidence packet record actual feature versions?
Remote Git query/checksum and other Dockerfile/build features are version-sensitive, so compatibility must be proven rather than assumed.
Official references and version notes
-
Build context
— authoritative behavior for local directories, Git repositories,
tarballs, stdin/empty contexts,
.dockerignore, Dockerfile-specific ignore files, Git URL queries/checksums, and named contexts. -
docker buildx build—--build-context, progress, outputs, metadata, and accepted named-context source types. -
Optimize cache usage
— why a small context improves transfer and cache behavior and how
.dockerignorereduces unnecessary input. -
Dockerfile reference
— how
COPY,ADD, andRUN --mountconsume build inputs. - Build best practices — source-control, cache, image, and reproducibility guidance.
- Docker Engine 29 release notes — current Engine baseline and fixes.
- Buildx releases — current Buildx feature/compatibility history.
- BuildKit releases — current BuildKit and built-in Dockerfile frontend releases.
Version-sensitive statements were rechecked against primary
documentation on 2026-09-21. Docker Engine 29.8.1
is the current Engine 29 patch release at this checkpoint; Buildx
0.37.1 and BuildKit 0.33.0 are current upstream baselines observed
in the current Docker packaging/release stream, and BuildKit
0.33.0 includes the built-in Dockerfile frontend 1.27.0. Docker
documents structured Git URL queries with
checksum/commit as requiring Buildx
0.28.0+, Dockerfile 1.18.0+, and Docker Desktop 4.46.0+ where
Desktop is used. Labs therefore record the learner's actual
builder/frontend state and include a local simulation path instead
of assuming remote Git-query support or network access.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.