Chapter 1: Foundations
Topic 04

Images vs Containers

ConceptImages

This is the distinction the whole book turns on, and getting it wrong is the source of more beginner confusion than any other single thing in Docker. An image is a read-only, layered, versioned filesystem plus metadata — the build-time artifact. A container is a running or stopped instance of an image with a thin writable layer on top — the runtime object.

The cleanest analogy is class and instance. The image is the class: defined once, immutable, identical wherever it is loaded. The container is an instance of that class: you create many from one image, each with its own state, and the image itself never changes when you run it. Build once, run many — the image is the noun, the container is the verb.

The Image — A Read-Only Template

An image is an ordered stack of read-only layers plus a configuration blob — the default command, environment variables, working directory, and exposed ports. Every layer is immutable, and the whole thing is content-addressed: a SHA-256 digest identifies the exact bytes, so an image pulled on your laptop is byte-for-byte the image pulled in CI and in production.

Nothing you do with a running container alters the image. The layers are shared, read-only, and frozen at build time. When you want the application to behave differently — a new dependency, a patched library, a changed default command — you build a new image; you do not edit the old one. An image is a snapshot, not a workspace.

The Container — A Writable Layer on Top

docker run takes an image's read-only layers, stacks one thin read-write layer on top, and starts the process. Everything the process writes — log files, temp files, a row inserted into a SQLite file, a downloaded asset — lands in that top writable layer, never in the image's frozen layers below. The image is shared and untouched; the writable layer belongs to this one container.

That writable layer is the container's entire mutable identity, and it is born empty and dies with the container. Remove the container with docker rm and the layer is discarded along with everything written into it. The read-only layers underneath are unaffected — they belong to the image and are still there for the next container.

One image, the layers each container adds
Image
An ordered stack of read-only layers plus config, addressed by digest. Immutable, shared, identical everywhere it is pulled.
Container
The image's layers plus one thin writable layer and a running process. The writable layer is discarded when the container is removed.

One Image, Many Containers

Launch ten containers from the same image and they share its read-only layers on disk and in the kernel's page cache — the layers are stored once, not copied ten times. The containers differ only in their individual writable layers and their runtime configuration: the ports they publish, the environment variables they get, the name they carry.

This is why starting another container from an existing image is nearly free in both disk and time. There is no copy of the image to make; the daemon adds an empty writable layer and forks a process. The same property is what makes containers worth scaling horizontally — you are not duplicating gigabytes, you are adding a thin layer over bytes that already exist.

The Lifecycle Boundary

docker build produces an image. docker run and docker create produce a container. docker commit turns a container back into an image, though that path is rare and usually a mistake. Each command lives firmly on one side of the image/container line, and keeping the two sides straight is most of what it takes to stop being confused by Docker.

The classic beginner error is conflating "rebuild the image" with "restart the container." Restarting a container reuses its existing writable layer and runtime config — same instance, same accumulated state. Rebuilding the image and running a fresh container starts from an empty writable layer with the new image's contents — different instance, prior changes gone. The two operations look similar at the command line and do entirely different things to in-container state.

Why Data Dies With the Container

Because every write lands in the disposable writable layer, removing a container deletes everything it wrote. This is not a bug or a limitation to work around — it is the direct, intended consequence of the image/container split. The container is meant to be cattle, and cattle do not carry durable state.

For Driftwood this matters the moment its database enters the picture. Store the database files inside the db container's writable layer and the first docker rm takes every bookmark with it. Durable data has to live in a volume — storage that exists outside the container's lifecycle, which Chapter 6 covers in full. For now the rule is enough: the writable layer is scratch space, and anything you cannot afford to lose does not belong there.

Image vs Container

Image — the immutable build artifact: read-only layers plus config, addressed by a tag or a content digest, produced by docker build, and shared by every container made from it. It never changes when you run it; changing the application means building a new image.

Container — a runtime instance: the image's read-only layers, plus one thin writable layer, plus a running process, created by docker run. Build once and run many; the writable layer holds the container's mutable state and is discarded when the container is removed. Class versus instance, all the way down.

Common Mistakes
  • Editing files inside a running container and expecting the change to persist — it lives only in that container's writable layer and vanishes on docker rm; the fix belongs in the Dockerfile and a rebuilt image, not in a live edit.
  • Confusing docker restart with running a fresh container — restart reuses the same writable layer and keeps accumulated state, while a fresh docker run starts from an empty layer with prior changes gone.
  • Using docker commit to snapshot a hand-tweaked container as your way to produce images — the result is opaque and unreproducible, with no record of how it was built; images should come from a Dockerfile in version control.
  • Storing the Driftwood database inside the db container's filesystem — replacing the container loses every row; the data must live on a volume from the very first run, not in the writable layer.
Best Practices
  • Treat every image as immutable and rebuild it to change anything, rather than mutating a running container and hoping the change survives a restart or replacement.
  • Produce every image from a Dockerfile under version control so it is reproducible, reviewable, and traceable to a commit — never from docker commit.
  • Keep all durable state in volumes and accept that the container's writable layer is scratch space that disappears on removal, so nothing irreplaceable ever lands there.
  • Reason about image versus container the way you reason about class versus instance — define the template once, instantiate it freely, and never confuse the two.
Comparable tools Podman · containerd · nerdctl every OCI tool shares this image/container split AMI · VM template the closest VM-world analogy — built once, booted into many instances A class vs an instance the programming-language analogy that maps exactly

Knowledge Check

Which statement captures the relationship between an image and a container?

  • An image is an immutable template and a container is a running instance of it, like a class and its instances
  • A container is the immutable template and an image is a mutable running instance of it, like a class and its objects
  • An image and a container are the same underlying object, just named differently before and after it starts running
  • Each container gets its own private full copy of the image that it solely owns and can modify freely at will

When a process inside a running container writes a file, where does that write actually go?

  • Into the container's thin writable layer on top of the image's read-only layers
  • Into the image's layers, modifying the image for every other container using it
  • Directly onto a persistent volume that Docker creates automatically for every write
  • Nowhere — a container's filesystem is fully read-only and the write silently fails

Why is launching a tenth container from an image you already have nearly free?

  • All containers share the image's read-only layers on disk; only a new empty writable layer and a process are added
  • Docker makes a fast compressed copy of the entire image on disk for each and every new container it launches
  • The tenth container is automatically built much smaller than the first nine in order to save disk space
  • All ten of the containers run together inside one shared memory space on the host rather than as ten separate, independent host processes

Why is using docker commit to produce your images considered an anti-pattern?

  • It snapshots a hand-tweaked container with no reproducible build record, unlike a Dockerfile in version control
  • Images produced by docker commit cannot be run at all and will simply refuse to start when invoked
  • It silently discards all of the container's changes, so the committed image always comes out completely empty
  • Committed images always come out far larger on disk than the very same application image built cleanly from an equivalent Dockerfile

You got correct