Building Docker Images
Learn to create efficient, secure, and production-ready Docker images using Dockerfiles.The Dockerfile
ADockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.
Basic Structure
Key Instructions
| Instruction | Description | Example |
|---|---|---|
FROM | Base image to start from | FROM ubuntu:22.04 |
WORKDIR | Sets working directory | WORKDIR /app |
COPY | Copies files from host to image | COPY . . |
RUN | Executes command during build | RUN apt-get update |
ENV | Sets environment variables | ENV NODE_ENV=production |
EXPOSE | Documents listening ports | EXPOSE 80 |
CMD | Default command to run | CMD ["npm", "start"] |
ENTRYPOINT | Main executable | ENTRYPOINT ["python"] |
Image Layers & Caching
Docker images are built from layers. Each instruction creates a new layer. Order matters! Put least frequently changed instructions at the top to maximize cache hits.Multi-Stage Builds
Drastically reduce image size by separating build tools from runtime artifacts.Example: Go Application
- Builder image: ~800MB (contains Go compiler, source code)
- Runtime image: ~15MB (contains only binary and minimal OS)
Building & Tagging
Managing Images
Best Practices
Use Alpine Images
Use Alpine Images
Start with
alpine based images (e.g., node:alpine, python:alpine) to keep images small and secure.Don't Run as Root
Don't Run as Root
Create a non-root user and switch to it with
USER instruction.Use .dockerignore
Use .dockerignore
Exclude files like
node_modules, .git, and secrets from the build context.Advanced Dockerfile Techniques
BuildKit Features
Enable BuildKit for modern features:Cache Mounts (Speed Up Builds)
Mount package manager caches to speed up repeated builds:Secret Mounts (Don’t Bake Secrets!)
Access secrets during build without storing in layer:SSH Mounts (Clone Private Repos)
Image Security Scanning
Docker Scout
Trivy
Best Practices for Secure Images
Distroless Images
Minimal images containing only your app and runtime dependencies. No shell, no package manager.| Base Image | Size | Attack Surface |
|---|---|---|
ubuntu:22.04 | ~77MB | High |
alpine:3.19 | ~7MB | Medium |
distroless/static | ~2MB | Minimal |
scratch | 0MB | None (just your binary) |
Image Optimization Checklist
Reduce Layer Count
Reduce Layer Count
Combine RUN commands to reduce layers:
Order Commands for Cache
Order Commands for Cache
Put least-changing commands first:
Use Multi-Stage Builds
Use Multi-Stage Builds
Keep build tools out of final image:
Interview Questions & Answers
What is a multi-stage build and why use it?
What is a multi-stage build and why use it?
Multi-stage builds use multiple FROM statements:
- Build stage: Has compilers, dev dependencies
- Runtime stage: Has only the built artifact
- Smaller final image (MBs vs GBs)
- Fewer vulnerabilities (no build tools)
- Single Dockerfile for build and runtime
How does Docker layer caching work?
How does Docker layer caching work?
Each instruction creates a layer. Docker caches layers and reuses them if:
- The instruction hasn’t changed
- All previous layers are cached
- Putting changing content (COPY .) last
- Copying dependency files separately before code
What is the difference between ADD and COPY?
What is the difference between ADD and COPY?
| Feature | COPY | ADD |
|---|---|---|
| Copy local files | ✓ | ✓ |
| Auto-extract tar | ✗ | ✓ |
| Download URLs | ✗ | ✓ |
| Preferred | ✓ | ✗ |
How do you reduce Docker image size?
How do you reduce Docker image size?
- Use Alpine/distroless base images
- Multi-stage builds to exclude build tools
- Combine RUN commands to reduce layers
- Clean up in the same layer (
rm -rf /var/cache/*) - Use .dockerignore to exclude unnecessary files
- Don’t install debugging tools in production
What is a dangling image?
What is a dangling image?
An image with no tag (shows as
<none>:<none>).Causes:- Rebuilding with same tag (old image becomes dangling)
- Intermediate build stages
How do you handle secrets in Docker builds?
How do you handle secrets in Docker builds?
Never do this:Do this instead:
- Use BuildKit secret mounts
- Pass at runtime:
docker run -e API_KEY=secret - Use Docker secrets (Swarm) or Kubernetes secrets
Common Pitfalls
Next: Docker Networking →