Bird
Raised Fist0
Dockerdevops~15 mins

Reducing final image size by 80 percent in Docker - Deep Dive

Choose your learning style10 modes available
Overview - Reducing final image size by 80 percent
What is it?
Reducing the final image size means making your Docker container images much smaller. This helps them download faster, use less storage, and start quicker. It involves techniques like choosing smaller base images, cleaning up unnecessary files, and using multi-stage builds. Smaller images are easier to share and deploy.
Why it matters
Without reducing image size, Docker images can become very large, causing slow downloads and wasting storage. This slows down development, testing, and deployment, especially in cloud or limited bandwidth environments. Smaller images save time and money, making software delivery smoother and more efficient.
Where it fits
Before learning this, you should understand basic Docker concepts like images, containers, and Dockerfiles. After mastering image size reduction, you can explore advanced Docker optimizations, container security, and orchestration with Kubernetes.
Mental Model
Core Idea
A Docker image is like a packed suitcase, and reducing its size means packing only what you truly need to travel light and move fast.
Think of it like...
Imagine packing for a trip: if you bring everything you own, your suitcase is heavy and hard to carry. But if you pack only essentials, your suitcase is light, easy to carry, and you can move quickly. Docker images work the same way.
┌─────────────────────────────┐
│       Docker Image           │
│ ┌───────────────┐           │
│ │ Base Image    │           │
│ ├───────────────┤           │
│ │ Application   │           │
│ │ Dependencies  │           │
│ └───────────────┘           │
│                             │
│  ↓ Remove unused files       │
│  ↓ Use smaller base images   │
│  ↓ Multi-stage builds        │
│                             │
│ ┌───────────────┐           │
│ │ Smaller Image │           │
│ └───────────────┘           │
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Docker Image Basics
🤔
Concept: Learn what a Docker image is and what it contains.
A Docker image is a snapshot of a filesystem with your app and everything it needs to run. It includes a base operating system layer, your application code, and any libraries or tools your app requires. Images are built using Dockerfiles, which list instructions to assemble the image step-by-step.
Result
You know that images are layered filesystems containing all app dependencies.
Understanding that images are layered helps you see why removing or optimizing layers reduces size.
2
FoundationWhy Image Size Affects Performance
🤔
Concept: Learn how image size impacts download, storage, and startup speed.
Large images take longer to download and use more disk space. This slows down starting containers and increases cloud storage costs. Smaller images start faster and save bandwidth, making development and deployment more efficient.
Result
You realize that smaller images improve speed and reduce resource use.
Knowing the real-world impact of image size motivates optimizing your Dockerfiles.
3
IntermediateChoosing Minimal Base Images
🤔Before reading on: do you think using a full OS base image or a minimal base image results in smaller final images? Commit to your answer.
Concept: Using smaller base images reduces the starting size of your Docker image.
Instead of using large base images like ubuntu or centos, use minimal ones like alpine or scratch. Alpine is a tiny Linux distribution with only essential packages. Scratch is an empty image, letting you add only what you need. This drastically cuts image size.
Result
Your image size drops significantly by starting with a smaller base.
Understanding base image choice is key because it forms the foundation of your image size.
4
IntermediateCleaning Up Unnecessary Files
🤔Before reading on: do you think leftover package manager caches and temporary files increase or decrease image size? Commit to your answer.
Concept: Removing temporary files and caches during image build reduces final size.
When installing packages, package managers often leave caches or temp files. If you don't delete them, they stay in the image. Use commands like 'apt-get clean' or 'rm -rf /var/lib/apt/lists/*' after installing. Also, delete build tools or docs not needed at runtime.
Result
The image size shrinks by removing files not needed after build.
Knowing to clean up during build prevents hidden bloat that silently inflates images.
5
IntermediateUsing Multi-Stage Builds
🤔Before reading on: do you think building and running your app in the same image is more or less efficient than using multi-stage builds? Commit to your answer.
Concept: Multi-stage builds let you compile or build in one stage, then copy only the final app to a smaller image.
In a multi-stage Dockerfile, the first stage contains all build tools and dependencies. After building, you copy only the necessary output (like a binary) to a clean, minimal base image in the final stage. This removes all build-time files from the final image.
Result
Final images are much smaller because they contain only runtime essentials.
Understanding multi-stage builds unlocks powerful size reduction by separating build and runtime environments.
6
AdvancedMinimizing Layers and Combining Commands
🤔Before reading on: do you think combining multiple RUN commands into one affects image size? Commit to your answer.
Concept: Each Dockerfile instruction creates a new layer; combining commands reduces layers and size.
Docker images are built in layers. Each RUN, COPY, or ADD creates a new layer. If you install packages in one RUN command and clean caches in another, the cache files remain in the earlier layer. Combining commands with '&&' lets you install and clean in one layer, reducing size.
Result
Images have fewer layers and less leftover data, making them smaller.
Knowing how layers work helps you write Dockerfiles that avoid hidden bloat.
7
ExpertAdvanced Tricks: Using Scratch and Distroless
🤔Before reading on: do you think using scratch or distroless images requires more or less manual setup? Commit to your answer.
Concept: Scratch and distroless images are ultra-minimal but need careful app preparation.
Scratch is an empty image with no OS, so you must include all dependencies your app needs. Distroless images contain only your app and its runtime dependencies without package managers or shells. They reduce attack surface and size but require static binaries or careful dependency management.
Result
Final images can be tiny and secure but need advanced setup.
Understanding these ultra-minimal images reveals trade-offs between size, security, and complexity.
Under the Hood
Docker images are built as layers stacked on each other. Each Dockerfile instruction creates a new layer that stores changes like added files or installed packages. When you build an image, Docker caches these layers. The final image size is the sum of all layers. Cleaning files in a later layer does not remove them from earlier layers, so combining commands or using multi-stage builds avoids leftover data. Multi-stage builds create temporary images for building, then copy only needed artifacts to the final image, leaving build dependencies behind.
Why designed this way?
Docker uses layered images to speed up builds and downloads by reusing unchanged layers. This design balances efficiency and flexibility. Multi-stage builds were introduced to separate build and runtime environments, solving the problem of large images caused by leftover build tools. Minimal base images like alpine and scratch exist to give developers control over size and security, trading off convenience for leaner images.
┌───────────────┐
│ Dockerfile    │
├───────────────┤
│ RUN apt-get   │
│ install ...   │
├───────────────┤
│ RUN rm cache  │
├───────────────┤
│ COPY app      │
└───────────────┘
       ↓
┌───────────────┐
│ Layer 1: OS   │
├───────────────┤
│ Layer 2: apt  │
│ packages     │
├───────────────┤
│ Layer 3: rm   │
│ cache files  │
├───────────────┤
│ Layer 4: app │
└───────────────┘

Note: cache files remain in Layer 2 despite removal in Layer 3.

Multi-stage build:
Stage 1: Build with tools
Stage 2: Copy only final app
Final image: minimal layers, no build tools.
Myth Busters - 4 Common Misconceptions
Quick: Does deleting files in a later Dockerfile layer remove them from the final image? Commit yes or no.
Common Belief:Deleting files in a later layer completely removes them from the final image.
Tap to reveal reality
Reality:Files deleted in a later layer still exist in earlier layers, so they remain in the final image and do not reduce size.
Why it matters:This misunderstanding leads to images larger than expected, wasting storage and bandwidth.
Quick: Is using the 'latest' tag for base images always safe for small image sizes? Commit yes or no.
Common Belief:Using 'latest' tag ensures you get the smallest and most optimized base image.
Tap to reveal reality
Reality:'Latest' can point to large or unstable images; it may increase size or cause build inconsistencies.
Why it matters:Relying on 'latest' can cause unexpected image bloat and unpredictable builds.
Quick: Do multi-stage builds always make images smaller regardless of how you use them? Commit yes or no.
Common Belief:Any use of multi-stage builds automatically reduces image size.
Tap to reveal reality
Reality:If you copy unnecessary files or don't clean build artifacts, multi-stage builds won't reduce size effectively.
Why it matters:Misusing multi-stage builds can give a false sense of optimization while images remain large.
Quick: Can you always use scratch base images for any application without changes? Commit yes or no.
Common Belief:Scratch images work out-of-the-box for all apps and reduce image size drastically.
Tap to reveal reality
Reality:Scratch requires static binaries and no OS dependencies; many apps need modification to run on scratch.
Why it matters:Trying to use scratch without preparation leads to broken containers and wasted effort.
Expert Zone
1
Layer caching can cause unexpected large images if intermediate files are not cleaned in the same RUN command.
2
Using distroless images improves security by removing shells and package managers, reducing attack surface beyond just size.
3
Combining multi-stage builds with build cache optimizations can speed up CI/CD pipelines while keeping images small.
When NOT to use
Avoid minimal base images like alpine or scratch if your app depends on complex OS features or dynamic libraries. In such cases, use standard base images or container slimming tools like Docker Slim. Also, multi-stage builds add complexity and may not be needed for simple apps.
Production Patterns
In production, teams use multi-stage builds to separate build and runtime, choose alpine or distroless bases for security and size, and automate image scanning for vulnerabilities. CI pipelines often cache layers to speed builds while enforcing size limits to control costs.
Connections
Software Packaging
Both involve bundling only necessary components to reduce size and improve portability.
Understanding how software packages include dependencies helps grasp why Docker images should be minimal and clean.
Supply Chain Management
Reducing image size is like optimizing supply chains to remove waste and improve delivery speed.
Knowing supply chain principles clarifies why removing unnecessary parts speeds up software delivery.
Minimalism in Design
Both focus on keeping only essential elements to improve efficiency and user experience.
Appreciating minimalism helps understand the value of lean Docker images for faster, cleaner deployments.
Common Pitfalls
#1Leaving package manager caches in the image increases size unnecessarily.
Wrong approach:RUN apt-get update && apt-get install -y curl
Correct approach:RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
Root cause:Not cleaning caches after installation leaves large temporary files in image layers.
#2Using multiple RUN commands for install and cleanup creates extra layers with leftover data.
Wrong approach:RUN apt-get install -y build-essential RUN rm -rf /var/lib/apt/lists/*
Correct approach:RUN apt-get install -y build-essential && rm -rf /var/lib/apt/lists/*
Root cause:Each RUN creates a layer; cleanup in a separate layer does not remove files from previous layers.
#3Copying entire build directory in multi-stage builds instead of only needed files bloats final image.
Wrong approach:COPY --from=builder /app /app
Correct approach:COPY --from=builder /app/myapp-binary /app/myapp-binary
Root cause:Copying unnecessary files from build stage adds unwanted data to final image.
Key Takeaways
Docker images are built in layers; each instruction adds size that can accumulate if not managed.
Choosing minimal base images and cleaning up during build drastically reduces final image size.
Multi-stage builds separate build and runtime environments, allowing only essential files in the final image.
Combining commands in Dockerfiles prevents leftover files in intermediate layers, keeping images lean.
Ultra-minimal images like scratch and distroless offer smallest sizes but require advanced preparation.

Practice

(1/5)
1. What is the main benefit of using multi-stage builds in Docker to reduce image size?
easy
A. It allows copying only necessary files to the final image, reducing size.
B. It speeds up the build process by running all commands in one stage.
C. It automatically compresses the image layers without manual steps.
D. It enables running multiple containers from one image simultaneously.

Solution

  1. Step 1: Understand multi-stage builds purpose

    Multi-stage builds let you use one stage to build your app and another to create a smaller final image.
  2. Step 2: Identify how size is reduced

    By copying only the needed files from the build stage to the final stage, unnecessary build tools and files are excluded.
  3. Final Answer:

    It allows copying only necessary files to the final image, reducing size. -> Option A
  4. Quick Check:

    Multi-stage builds copy only needed files [OK]
Hint: Remember: multi-stage copies only needed files [OK]
Common Mistakes:
  • Thinking multi-stage speeds up build time
  • Assuming multi-stage compresses layers automatically
  • Confusing multi-stage with running multiple containers
2. Which Dockerfile syntax correctly starts a multi-stage build with a small final image?
easy
A. FROM node:18-slim RUN npm install COPY /app /app
B. FROM node:18-slim AS build RUN npm install FROM node:18 COPY --from=build /app /app
C. FROM node:18 RUN npm install COPY /app /app
D. FROM node:18 AS build RUN npm install FROM node:18-slim COPY --from=build /app /app

Solution

  1. Step 1: Identify multi-stage build syntax

    Multi-stage builds use 'AS' to name stages and 'COPY --from=stage' to copy files.
  2. Step 2: Check base images for build and final stages

    FROM node:18 AS build RUN npm install FROM node:18-slim COPY --from=build /app /app uses full node image for build and smaller node:18-slim for final, which reduces size.
  3. Final Answer:

    FROM node:18 AS build RUN npm install FROM node:18-slim COPY --from=build /app /app -> Option D
  4. Quick Check:

    Correct multi-stage syntax with smaller final image [OK]
Hint: Use 'AS' to name build stage and copy from it [OK]
Common Mistakes:
  • Not using 'AS' to name build stage
  • Using larger base image in final stage
  • Copying files without specifying source stage
3. Given this Dockerfile snippet, what will be the approximate size difference between the final image and the build stage image?
FROM golang:1.20 AS build
WORKDIR /app
COPY . .
RUN go build -o myapp
FROM alpine:latest
COPY --from=build /app/myapp /myapp
CMD ["/myapp"]
medium
A. Final image is about 80% smaller than the build image.
B. Final image is larger than the build image.
C. Final image and build image are about the same size.
D. Final image is about 20% smaller than the build image.

Solution

  1. Step 1: Analyze base images used

    The build stage uses golang:1.20 (large image with build tools), final uses alpine (very small).
  2. Step 2: Understand what is copied to final image

    Only the compiled binary is copied, excluding all build dependencies, drastically reducing size.
  3. Final Answer:

    Final image is about 80% smaller than the build image. -> Option A
  4. Quick Check:

    Copying only binary to alpine reduces size ~80% [OK]
Hint: Copy only binary to tiny base image for big size drop [OK]
Common Mistakes:
  • Assuming final image includes build tools
  • Thinking final image is bigger due to alpine
  • Believing size difference is minimal
4. You wrote this Dockerfile to reduce image size but the final image is still large:
FROM python:3.12 AS build
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
FROM python:3.12
COPY --from=build /app /app
CMD ["python", "/app/app.py"]
What is the main issue causing the large final image?
medium
A. You forgot to run pip install in the final stage.
B. The final stage uses the full python:3.12 image instead of a smaller base.
C. COPY command syntax is incorrect and copies nothing.
D. The requirements.txt file is missing in the build stage.

Solution

  1. Step 1: Check base images in build and final stages

    Both stages use python:3.12, which is a large image; no size reduction from multi-stage.
  2. Step 2: Identify how to reduce size

    Using a smaller base like python:3.12-slim or alpine in the final stage reduces image size significantly.
  3. Final Answer:

    The final stage uses the full python:3.12 image instead of a smaller base. -> Option B
  4. Quick Check:

    Final stage base image too large [OK]
Hint: Use smaller base image in final stage to shrink size [OK]
Common Mistakes:
  • Thinking pip install must run in final stage
  • Assuming COPY syntax is wrong
  • Believing requirements.txt missing causes large image
5. You want to reduce your Docker image size by 80%. Your app requires Node.js to build but only needs the compiled files to run. Which Dockerfile approach best achieves this?
hard
A. Use multi-stage build: first stage with node:alpine to build, second stage with node:latest to run.
B. Use a single stage with node:latest and delete node_modules after build.
C. Use multi-stage build: first stage with full node image to build, second stage with node:alpine copying only build output.
D. Use a single stage with node:alpine and install build tools at runtime.

Solution

  1. Step 1: Understand build and runtime needs

    Building requires full Node.js image with tools; running only needs compiled files and a small base.
  2. Step 2: Choose multi-stage build with appropriate images

    First stage uses full node image to build; second stage uses smaller node:alpine image copying only build output to reduce size.
  3. Final Answer:

    Use multi-stage build: first stage with full node image to build, second stage with node:alpine copying only build output. -> Option C
  4. Quick Check:

    Multi-stage with full build image and small runtime image [OK]
Hint: Build with full image, run with small image copying only output [OK]
Common Mistakes:
  • Using single stage and deleting files later
  • Building on small image lacking tools
  • Running on large image unnecessarily
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard