fivenines
25/40

Guided Problem

MiniDock Build 20: Choose Storage by Required Lifetime

Time
20m
Level
foundation
Artifacts
not specified
Progress0%
Lesson 25 · Storage

Volumes, Binds, tmpfs

Design claim: Storage selection begins with lifetime and ownership, because writable layers, volumes, bind mounts, and tmpfs make different promises.

Starting model

  • You can report service readiness and recovery without confusing health with process existence.
  • The useful vocabulary at this point is deliberately small: engine-managed durable mount, bind mount, tmpfs, mount path.

The first storage question is how long

ParcelFlow needs disposable scratch space, engine-managed durable database data, and explicit access to a host configuration file. Storage design starts with who owns the bytes and how long they must live. Backend mechanics come only after those promises are explicit.

The tempting shortcut is straightforward: mount every writable path through one generic persistent storage option. The shortcut treats every writable path as if mounting and ownership were the same relationship. Some data must vanish with the container, some must outlive it, some is owned by the host, and some must never reach disk. Replacement or cleanup then reveals that consumer lifetime and data lifetime were never equivalent.

Four writable surfaces, four contracts

The engine offers a container writable layer, managed volumes, host bind mounts, and memory-backed tmpfs as distinct lifetime contracts. The mechanism gives the durable resource or driver its own contract so containers can attach without silently inheriting ownership.

Read the ownership edges separately from mount edges; they answer different cleanup and recovery questions.

Architecture — three mounts into one container
  flowchart LR
    subgraph C["container filesystem view"]
      P1["/var/lib/db"]
      P2["/src"]
      P3["/run/secrets"]
      P4["everything else
(overlay, dies with container)"] end V[("volume 'dbdata'
engine-managed area")] --> P1 H["/home/user/project
(exact host path)"] --> P2 T["tmpfs (RAM only)"] --> P3 style V fill:#eaf1fe,stroke:#1d63ed style P4 fill:#fff8ec,stroke:#f2ddb0

It compares writable layer, managed volume, host bind, and tmpfs ownership. Its central claim is that storage lifetime and owner are selected explicitly rather than inferred from the container that currently mounts it; the labels therefore describe authority rather than decorative grouping.

Mounting does not transfer ownership

Each mount type answers "who owns this data?" differently. A volume is a directory the engine owns in its own storage area — created, listed, and removed via the API, portable across hosts because nothing about the host's layout leaks into the container config. Best default for databases and anything precious. A bind mount maps an exact host path the user owns — perfect for live-editing source code in development, but host-specific and a security door (the container sees real host files). tmpfs lives in RAM, owned by nobody: gone at stop, ideal for secrets and scratch space that must never touch disk. All three bypass the overlay entirely — native write speed, no copy-up.

The requested mount type determines who selects the path, who owns cleanup, whether bytes persist, and how replacement containers regain access. Track selection, mounting, use, and cleanup as distinct responsibilities rather than one container operation.

The second figure tests the same model in motion: it follows container replacement and shows which data survives or disappears.

Architecture — the decision path
  flowchart TB
    Q1{"must the data
survive the container?"} Q1 -- no --> Q2{"must it never
touch disk?"} Q2 -- yes --> T["tmpfs"] Q2 -- no --> O["overlay is fine
(no mount needed)"] Q1 -- yes --> Q3{"does a specific HOST path
matter to you?"} Q3 -- "yes (dev loop, host config)" --> B["bind mount"] Q3 -- "no — engine may place it" --> VOL["volume (default choice)"] style VOL fill:#eaf1fe,stroke:#1d63ed

It follows container replacement and shows which data survives or disappears. The ordering is valid only when it continues to preserve the stated invariant under retries and interruption.

Replacement exposes the real lifetime

A scan database container is replaced, so its durable data must reattach while scratch files and memory-only secrets disappear. A precise storage boundary reports incomplete cleanup without erasing data or claiming a backend action succeeded.

Storage lifetime and owner are selected explicitly rather than inferred from the container that currently mounts it. The invariant states lifetime and authority independently of the currently selected backend.

Make MiniDock ask who owns the bytes

MiniDock chooses storage by the data promise before selecting a backend. MiniDock can choose a storage mechanism only after preserving that ownership rule.

What carries forward

  • Storage lifetime and owner are selected explicitly rather than inferred from the container that currently mounts it.
  • Choose storage ownership and lifetime independently from a container's writable layer.
  • 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.