Skip to main content

Command Palette

Search for a command to run...

Day 16 - Multi-Stage Docker Builds & Distroless Images

Updated
6 min read

🚀 Reduce Image Size by 800% and Improve Security


🎯 1. Objective

In this session, we’ll learn:

  1. The concept of Multi-Stage Docker Builds

  2. The concept of Distroless (Destroyless) Images

Both concepts are closely related — using distroless images enhances the efficiency and security of multi-stage builds.


🧱 2. The Problem with Traditional Docker Builds

Let’s take a simple example:
You want to containerize a Python calculator application.

Typical Steps

  1. Start from a base image (e.g., ubuntu:latest)

  2. Set a working directory (optional)

  3. Install dependencies:

    • Python

    • pip

    • Required Python modules/packages

  4. Copy source code into the image

  5. Build and run the application (via CMD or ENTRYPOINT)

⚠️ Problem

Although this Dockerfile works, it’s inefficient:

  • The image includes the entire Ubuntu OS plus unnecessary packages (apt, curl, etc.)

  • These packages are only needed during build, not runtime

  • The final image becomes huge and slow to pull/run


⚙️ 3. Build vs. Run Phases

StagePurposeExample
Build StageCompiles or prepares the appInstalls compilers, dependencies
Run StageExecutes the final appNeeds only runtime environment

For instance:

  • A Java app needs JDK to build, but only JRE to run.

  • A Python app needs pip and libraries to build, but only Python runtime to run.

So, it’s wasteful to keep all build-time tools in the final image.


🧩 4. Docker’s Solution — Multi-Stage Builds

To solve this problem, Docker introduced multi-stage builds.

💡 Concept

You can split your Dockerfile into multiple stages, using multiple FROM statements in one file.

Each stage:

  • Builds a specific part of your application

  • Can copy artifacts (like binaries) to the next stage

  • Keeps the final image minimal


🏗️ 5. Example: Two-Stage Dockerfile

Stage 1 – Build Stage

FROM ubuntu AS build
RUN apt-get update && apt-get install -y python3 pip
COPY . /app
WORKDIR /app
RUN python3 setup.py build

Stage 2 – Final Stage

FROM python:3.10-slim
COPY --from=build /app/dist /app
CMD ["python3", "/app/main.py"]

Result:

  • The build tools (like apt, compilers, pip caches) are excluded

  • Only the necessary runtime (Python + your app) remains

  • Image size drastically reduces


🧮 6. Example: Multi-Stage Build for Complex App

Imagine a 3-tier application:

  • Frontend (React)

  • Backend (Java Spring Boot)

  • Database (MySQL)

Traditional Method:

  • All dependencies (Node.js, JDK, MySQL client) installed in one image → ~1 GB+.

With Multi-Stage Build:

  • Each part built in separate stages:

    • Stage 1 → Frontend build (React)

    • Stage 2 → Backend build (Java)

    • Stage 3 → Final stage (only Java runtime + built artifacts)

  • Final image = ~150 MB

Result:
Image size reduced by ~85–90% with cleaner, modular build process.


📉 7. Image Size Comparison Example

TypeDescriptionApprox. Size
Traditional single-stageubuntu + go + source + runtime861 MB
Multi-stage + DistrolessOnly runtime + binary1.83 MB
Reduction~800× smaller 🚀

⚙️ 8. Multi-Stage Docker Syntax Example

# Stage 1: Build
FROM ubuntu AS build
RUN apt-get install -y golang
COPY . /src
WORKDIR /src
RUN go build -o calculator calculator.go

# Stage 2: Final (Distroless)
FROM scratch
COPY --from=build /src/calculator /
ENTRYPOINT ["/calculator"]

Explanation:

  • AS build → Creates a named stage

  • COPY --from=build → Copies artifact from build stage

  • FROM scratch → Uses an empty minimal image (distroless base)


🪶 9. What Are Distroless Images?

Definition

A Distroless Image is a very minimalistic base image that includes:

  • Only runtime binaries (e.g., Python runtime, Java runtime)

  • No package manager, no shell, no OS utilities

🔍 Examples

LanguageDistroless Image Example
Javagcr.io/distroless/java17
Pythongcr.io/distroless/python3
Node.jsgcr.io/distroless/nodejs
Goscratch (empty base, needs no runtime)

🧰 10. Why Distroless?

✅ Advantages

BenefitDescription
Smaller Image SizeRemoves all unnecessary OS layers
Higher SecurityNo package manager, shell, or vulnerable binaries
Faster DeploymentLightweight → faster pull/run
Best with Multi-Stage BuildsBuild heavy → final image minimal

🔒 11. Security Benefits

  • Traditional base images (like Ubuntu, CentOS) come with many system packages → higher attack surface.

  • Distroless images have no shell, no apt, no curl, etc.

  • Hackers can’t exploit missing tools.

  • Greatly reduces CVE (Common Vulnerability Exposure) count.

Example:

In interviews, you can say:
“We moved from Ubuntu-based containers to Python Distroless images, eliminating unnecessary system binaries and greatly reducing vulnerability exposure.”


🦴 12. Special Case: Go (Golang) Applications

  • Go produces statically compiled binaries.

  • Doesn’t even need a runtime to execute.

  • Works perfectly with the scratch base image.

  • Final image size can be as small as 1–2 MB.

Hence, Go + Multi-Stage + Distroless = 💯 perfect combination.


🔍 13. Finding Distroless Images

Visit the official Google Distroless GitHub repository:
👉 https://github.com/GoogleContainerTools/distroless

There you’ll find folders for:

  • base, cc, java, python3, nodejs, etc.
    Each folder’s README.md lists the image name (e.g., gcr.io/distroless/java17).

🧾 14. Key Interview Points

QuestionShort Answer
What is a Multi-Stage Docker Build?A way to split a Dockerfile into multiple build stages and keep only the final runtime stage.
What are Distroless Images?Minimal base images without OS or shell, containing only runtime dependencies.
Benefits of Multi-Stage BuildsSmaller, faster, modular images.
Benefits of Distroless ImagesSecurity, minimalism, reduced vulnerabilities.
How many stages can a multi-stage build have?Unlimited, but only one final stage is used to run the container.
Which base image is the most minimal?scratch (completely empty).

🧠 15. Summary

ConceptKey Idea
Traditional DockerfileInstalls build + runtime tools in one image → large & insecure
Multi-Stage Docker BuildSeparates build & runtime stages → smaller & efficient
Distroless ImageRemoves OS layer entirely → minimal, secure runtime
ResultUp to 800× smaller, highly secure, production-ready images

Final Takeaway:

Using Multi-Stage Docker Builds + Distroless Images gives you:

  • Massive reduction in image size

  • Improved container startup speed

  • Drastically fewer security vulnerabilities

  • Best practice for all modern production-grade container builds

More from this blog

Dinesh's Blog

104 posts