containers · level 1

Docker Fundamentals

Image vs container. Layers, COW, Dockerfiles.

150 XP

Docker Fundamentals

A container is an isolated process running on top of a shared host kernel. An image is the frozen template those processes are launched from. The two words get used interchangeably in conversation, but they are very different objects on disk.

Analogy

Think of a bakery's frozen cookie dough. The sealed tube on the shelf is the image — inert, identical to every other tube off the line, and it can sit there forever. The warm cookies on the tray are containers — baked from a tube, eaten, gone. You can pull a dozen tubes off the shelf, bake them all at once, throw the crumbs away, and the tubes are still unchanged. That is why the same image can spawn a thousand identical processes on a thousand machines.

Image vs container

An image is a stack of read-only layers, each a tarball of filesystem changes, addressed by content hash.

A container is an image plus one writable layer on top. When you docker run nginx, Docker takes the nginx image, adds a thin scratch layer, and starts a process in it. Stop the container and the writable layer can be discarded — the image underneath is untouched.

docker images       # what's frozen on disk
docker ps           # what's currently running
docker ps -a        # including stopped containers

Layers and copy-on-write

Every layer-producing line in a Dockerfile (FROM, RUN, COPY, ADD, WORKDIR) adds one layer. Metadata lines (ENV, EXPOSE, CMD, ENTRYPOINT, USER, LABEL) change only the image config; they do not add filesystem layers.

When a container writes to a file that lives in a read-only layer, the storage driver copies the file up into the writable layer and modifies the copy. The original stays untouched. This is copy-on-write, and it's how ten containers from the same image can share 99% of their bytes on disk.

A minimal Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]

Five layers get written (FROM, WORKDIR, COPY, RUN, COPY), one metadata entry (CMD).

Order matters: each line's cache key is a hash of the previous state and the line itself. Change line 4 and lines 1–3 still hit the cache; everything from line 4 down is rebuilt. That's why dependency installs live before application source.

Multi-stage builds

A single Dockerfile can define multiple stages, each starting with its own FROM. Later stages can copy files from earlier stages; everything else is discarded.

FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN go build -o /app/server .

FROM gcr.io/distroless/static
COPY --from=build /app/server /server
ENTRYPOINT ["/server"]

The final image contains only the binary and the distroless base — no Go toolchain, no /bin/sh, no apt. That is both smaller and meaningfully safer — there's nothing in there for an attacker to work with.

Tags, digests, and pulling

docker pull alpine:3.19          # by tag (mutable)
docker pull alpine@sha256:…       # by digest (immutable)
docker run --rm -it alpine:3.19 sh

Tags are labels that the registry is free to repoint; digests are content-addressable and never change. Production pipelines should resolve tags to digests on build and ship the digest.

Inspecting images

docker image inspect alpine:3.19       # JSON: layers, env, entrypoint
docker history alpine:3.19             # layer-by-layer breakdown
docker run --rm -it alpine:3.19 sh     # exec a shell inside

docker history is particularly useful — it shows how each layer was created and how big it is, so you can see where the 400 MB of bloat came from.

Images are not VMs

A container does not boot a kernel, does not run init, does not have its own /boot. It is a tree of processes that the host kernel has placed into Linux namespaces (which is what makes ps show only the container's own processes) and cgroups (which is what enforces CPU and memory limits). Level 2 takes that apart.

Tools in the wild

6 tools
  • Dockerfree tier

    The reference container engine + CLI; `build`, `run`, `compose` are the daily verbs.

    cli
  • BuildKitfree tier

    Modern Docker builder with cache mounts, secrets, and concurrent layer builds.

    library
  • Podmanfree tier

    Daemonless, rootless Docker drop-in — friendly to security-conscious environments.

    cli
  • Divefree tier

    TUI for inspecting image layers; pinpoints exactly which COPY blew up your image size.

    cli
  • Trivyfree tier

    Aqua's vulnerability scanner for images, IaC, and SBOMs — runs in CI in seconds.

    cli
  • Multi-container dev environments from a single `docker-compose.yml` file.

    cli