fivenines
10/40

Theory Tutorial

Building Images

Time
10m
Level
not specified
Artifacts
theory + practice
Progress0%
Lesson 10 · Images

Building Images

Design claim: An image build is an ordered transformation from declared inputs to immutable snapshots, with an explicit boundary around each step.

Starting model

  • You can give containers independent writable views without copying or mutating shared image layers.
  • The useful vocabulary at this point is deliberately small: build instruction, temporary container, snapshot, layer diff.

A build should explain its history

A Dockerfile must produce a reviewable image history rather than mutate an unknown host into an undocumented state. Treat the release as data with identity and history, not as the accidental contents of one machine. Reuse is safe only after that data model is precise.

The tempting shortcut is straightforward: run build commands directly on the host and archive the final directory. The shortcut looks efficient until immutable history, shared content, or reproducibility becomes observable. Host execution leaks local tools and state into the result, obscures instruction boundaries, and makes intermediate failure difficult to reproduce. The constraint turns a convenient file operation into an identity or ordering bug.

Turn commands into immutable transitions

The builder's core loop is elegantly circular: to build an image, run containers. For each instruction — "copy these files in", "run this install command", "set this env var" — the builder starts a temporary container from the layers built so far, applies the instruction, and captures the result. Filesystem-changing instructions (COPY, RUN) produce a new layer (the upper dir, tarred). Metadata instructions (ENV, CMD, EXPOSE) touch only the config — no layer at all. The inputs are the build file plus a build context: the directory of files the client ships to the daemon, the only files COPY can ever see.

The builder applies instructions in order against a controlled root filesystem and commits filesystem changes as immutable layers with updated configuration. The mechanism makes inputs and resulting content explicit, allowing later stages to reuse facts instead of trusting names or mutable directories.

Read the structure from references toward immutable content, noting where ordering or private state changes the meaning of an otherwise shared object.

Architecture — the builder's loop
  flowchart LR
    BF["build file
(instruction list)"] --> B["builder"] CTX["build context
(files sent by client)"] --> B B --> TMP["temp container
from layers so far"] TMP -- "capture upper dir" --> NL["new layer"] NL -- "becomes base for
next instruction" --> TMP B --> CFG["image config
(cmd, env — no layers)"] NL --> IMG["final image:
layers + config + manifest"] CFG --> IMG

It maps ordered build instructions to successive image states. Its central claim is that every published build state corresponds to a completed prefix of declared instructions; the labels therefore describe authority rather than decorative grouping.

Each completed prefix becomes a valid state

The builder's core loop is elegantly circular: to build an image, run containers. For each instruction — "copy these files in", "run this install command", "set this env var" — the builder starts a temporary container from the layers built so far, applies the instruction, and captures the result. Filesystem-changing instructions (COPY, RUN) produce a new layer (the upper dir, tarred). Metadata instructions (ENV, CMD, EXPOSE) touch only the config — no layer at all. The inputs are the build file plus a build context: the directory of files the client ships to the daemon, the only files COPY can ever see.

Each instruction starts from the preceding snapshot, performs its declared operation, records the diff or metadata change, and hands a new state to the next instruction. Follow identity through the operation and ask which completed fact authorizes each reuse or transition.

The second figure tests the same model in motion: it shows temporary execution, snapshot commitment, and failure before publication.

Sequence — building COPY → RUN → CMD
  sequenceDiagram
    participant C as Client
    participant B as Builder (in daemon)
    participant T as Temp container
    C->>B: build (sends build file + context)
    B->>T: start from base image, then COPY app/ /app
    T-->>B: diff captured → layer 1
    B->>T: start from base+L1, then RUN install deps
    T-->>B: diff captured → layer 2
    B->>B: CMD "serve" → config only, no container needed
    B-->>C: image built: base + L1 + L2 + config
    note over B: each snapshot is a normal layer —
the image is its own build history

It shows temporary execution, snapshot commitment, and failure before publication. The ordering is valid only when it continues to preserve the stated invariant under retries and interruption.

Failure must not publish a half-step

An instruction fails after modifying its temporary environment, so no partially completed snapshot may become the image's next valid state. A partial or stale result must remain distinguishable from a complete image state; otherwise the cache or store begins to lie.

Every published build state corresponds to a completed prefix of declared instructions. The invariant is phrased in bytes, ownership, or completed prefixes so it remains true across storage implementations.

Give MiniDock a controlled builder

MiniDock's builder can expose instruction boundaries without leaking its temporary execution machinery into the image contract. MiniDock can adopt the content rule without preselecting the learner's attachment point.

What carries forward

  • Every published build state corresponds to a completed prefix of declared instructions.
  • Trace how an ordered build recipe becomes immutable layers plus runtime configuration.
  • The rejected shortcut remains a diagnostic: if the design starts depending on it again, the original constraint has probably been lost.
Next step

See what actually stuck.

Take the practice scenarios now.