Docker Images
Images are immutable, layered blueprints for containers. Learning how layers and build caching work is the key to fast, small and secure Docker images.
What is this?
A Docker image is a read-only template made of stacked filesystem layers. Each instruction in a Dockerfile creates one layer. When you build, Docker caches each layer; when you run, layers are mounted read-only and a thin writable layer is added on top.
Why do you need it?
- Layers make images shareable — the base OS layer is stored once and reused by every image built on it.
- Build caching speeds up iteration: unchanged layers are reused instead of rebuilt.
- Immutability means the artifact is identical in dev, staging and production.
- Smaller images transfer faster and start quicker.
Mental model
A photo negative
A Docker image
A negative is a fixed template; every print made from it is identical. Every container from an image starts from the same immutable state.
How it works
- The Dockerfile is a recipe of instructions, each becoming a layer in the final image.
- On build, Docker checks its cache: if the instruction and its parent layers are unchanged, the cached layer is reused.
- Changing a line invalidates that layer and every layer after it — so order matters.
- Images are identified by repository:tag and a content-addressable digest (sha256).
- A multi-stage build uses one image to compile and a separate slim image to run, dropping build toolchain weight.
Layers of a Docker image built with build cache.
Key commands
docker imagesList local images with their tags and sizes.
docker build -t myapp:1.0 .Build an image from the Dockerfile in the current directory.
docker build --no-cache -t myapp:1.0 .Rebuild without using any cached layers.
docker history myapp:1.0Show every layer in the image and its size.
docker rmi myapp:1.0Remove an image and its layers.
Examples
A lean Node.js Dockerfile
FROM node:20-alpineWORKDIR /appCOPY package*.json ./RUN npm ci --only=productionCOPY . .ENV NODE_ENV=productionUSER nodeEXPOSE 3000CMD ["node", "server.js"]Dependency files are copied before the source so npm ci is cached until deps change. The app runs as the non-root 'node' user, and the alpine base keeps the image small.
In production
- CI builds images once per commit and tags them with commit SHA for traceability.
- Multi-stage builds produce runtime-only images that exclude compilers and SDKs.
- Distroless and scratch base images minimize attack surface and size.
- Vulnerability scanning (Trivy, Grype) gates image promotion in the pipeline.
Best practices
- Order instructions from least to most frequently changing to maximize cache hits.
- Pin base image versions, never FROM node:latest.
- Use multi-stage builds and minimal bases (alpine, distroless, scratch).
- Add a .dockerignore to keep build context and secrets out of the image.
- Use COPY over ADD unless you need tar auto-extraction or remote URLs.
Common mistakes
- Copying source before dependencies, invalidating the npm ci cache on every change.
- Including secrets via ARG/ENV that end up in image layers.
- Running builds as root inside the image.
- Leaving debuggers, test files and .git in production images.
Common issues
failed to solve: process ... did not complete successfullyA RUN instruction's command exited non-zero.
Add a temporary RUN with the failing command and inspect output, or use docker build --no-cache --progress=plain.
ERROR: failed to authorize: failed to fetch anonymous tokenRegistry rate limit or no network from the build host.
Authenticate with docker login, retry, and prefer a smaller base image to reduce pull volume.
COPY failed: stat ... no such file or directoryPath is outside the build context or excluded by .dockerignore.
Verify the file exists inside the context directory and isn't in .dockerignore.
Debugging tips
- docker history to find which layer bloats the image.
- docker build --progress=plain to see exactly which steps ran or used cache.
- docker build --no-cache to rule out a poisoned cache.
- docker run --entrypoint sh IMAGE to explore the built filesystem.
Interview checkpoint
Hands-on lab
- Write an optimized Dockerfile
- Use build cache correctly
- Reduce final image size with a multi-stage build
- Inspect image layers
Build a Production-Ready Image
35 min · intermediate
Quick quiz
Which statement about Docker image layers is true?
What happens to the cache when you change COPY . . in the middle of a Dockerfile?
Cheat sheet
docker build -t app:tag .Build an imagedocker imagesList local imagesdocker history app:tagShow layer stackdocker rmi app:tagDelete an image