What’s the difference between a Docker image and a container, and how does layering work?
An image is a read-only, layered filesystem plus metadata (entrypoint, env vars, exposed ports). A container is a running instance of an image with one additional layer on top: a thin, writable layer. Everything the container writes at runtime, like log files or a temp cache, goes into that writable layer. The image underneath never changes.
How the layers are built
Each instruction in a Dockerfile that changes the filesystem (RUN, COPY, ADD) produces a new, immutable layer. Docker uses a union filesystem (overlay2 on most modern hosts) to stack these layers into a single logical filesystem. Layers are content-addressed, so if two images share a base (say, the same node:20-slim layer), Docker stores that layer once on disk and reuses it. That’s the entire mechanism behind fast pulls and small incremental pushes.
Best practice
Order Dockerfile instructions from least to most frequently changing. Dependency installation (npm ci, pip install) should happen before you COPY application source, so code changes don’t invalidate the dependency layer’s cache. Combine related RUN commands with && to avoid leaving intermediate junk (like apt cache) in its own layer, since a deleted file in a later layer doesn’t shrink the image, it just hides the file.
Edge case interviewers probe for
Ask what happens to the writable layer when the container is removed. Answer: it’s deleted with the container, which is exactly why you never store real data there, anything that needs to survive a restart or redeploy belongs in a volume or bind mount, not the container’s own filesystem.
Common mistake
Candidates often say “an image is like a class and a container is an instance,” which is directionally fine as an analogy but falls apart the moment the interviewer asks a follow-up about layers or storage drivers. Know the actual mechanism, not just the metaphor.
What the interviewer is checking
Whether you understand that images are immutable and containers are disposable. That single idea underlies why containers are supposed to be stateless, why CI can cache layers, and why you should never docker commit a running container as a deployment strategy.
Think of a Docker image like a recipe printed in a cookbook. The recipe itself never changes, it’s just words on a page. A container is what happens when you actually cook the recipe: now you have a real dish sitting on the counter, and if you add extra salt while eating, that change only affects your plate. The cookbook page is untouched, and the next time someone cooks from it, they start from the same original recipe.
The “layers” in an image are like a recipe built out of steps that get photocopied and stacked: step 1 might be “boil the pasta,” step 2 “add the sauce.” If two recipes both start with “boil the pasta,” a smart kitchen would only photocopy that step once and reuse it for both dishes, instead of writing it out twice. That’s exactly what Docker does with layers that are shared between images: it stores the shared part once and reuses it, which is why downloading a new image that shares a base with one you already have is fast.
And the “writable layer” on a container is just your dinner plate: it’s where the mess from actually using the thing goes. Throw the plate away (remove the container) and the recipe book (the image) is completely unaffected, ready for the next person to cook from.
Why interviewers ask this
It’s a filter question. Anyone who’s run docker run a few times can describe images and containers loosely; only people who’ve actually debugged a bloated image or a “why did my data disappear” incident understand layers and the writable layer well enough to answer the follow-ups.
What a strong answer signals
That you think about image size, build cache efficiency, and statelessness as defaults, not afterthoughts you reach for during an outage.
Common follow-ups
- How would you shrink this image’s size?
- What’s a multi-stage build and why use one?
- Where should application data actually live?
Advanced variation
“Walk me through what docker build does step by step, including caching,” which expects you to explain layer cache invalidation: the moment one instruction’s input changes, every layer after it rebuilds from scratch.
A real pattern from production: a Node.js API’s image was 1.2GB because the Dockerfile ran npm install (including devDependencies), copied the entire repo including test fixtures and a local `.git` folder, then never cleaned up. After splitting the build into a multi-stage Dockerfile (build dependencies in one stage, copy only the compiled output and production dependencies into a slim final stage) plus a `.dockerignore` file excluding `.git`, `tests/`, and `node_modules/`, the image dropped to 180MB, and CI pipeline time per deploy fell by roughly a third because pulling and pushing a smaller image over the network is the actual bottleneck in most deploy pipelines, not the build itself.
# --- build stage: has full toolchain, discarded after build ---
FROM node:20-slim AS builder
WORKDIR /app
# dependency layer cached separately from source changes
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# --- final stage: only what's needed to run ---
FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]- 1An image is immutable and layered; a container adds one writable layer on top and is disposable.
- 2Layers are shared across images by content hash, which is why pulls and disk usage are efficient.
- 3Order Dockerfile instructions so rarely-changing steps (dependencies) come before frequently-changing ones (source code).
- 4Anything written to a container’s writable layer is lost when the container is removed, use volumes for real persistence.
- 5Multi-stage builds keep the final image small by discarding build-only tooling from the shipped layers.