Slimming Down Docker Images

Avirup GhosalAvirup Ghosal
3 min read

Introduction

Docker images play a key role in speeding up deployments and scaling. However achieving lean and optimized images can be challenging, especially when using base images that come with a lot of unnecessary components. This blog explores how multistage builds and distroless images can help reduce Docker image sizes while maintaining security and performance. You can find the complete source code and examples for this blog in my GitHub repository: https://github.com/avirup-ghosal/Multistage-DockerBuild

The Impact of Docker Image Size

Large Docker images can lead to slower build times, increased attack surface, and more time-consuming deployments. Whether you are deploying to a cloud environment or using CI/CD pipelines. Optimizing your docker images is crucial.

Multi-stage Builds: Building Efficiently

Multi-stage builds allow you to use multiple FROM statements in your Dockerfile. Each FROM instruction can use a different base and begin a new stage of build. You can selectively copy elements from one stage to another, leaving behind unnecessary parts in the final Docker image. This helps to drastically decrease the image size.

Example of multi-stage build

Here’s an example of using a multi-stage build approach in a Dockerfile for a Node.js application:

# Dockerfile with multi-stage build
# Stage1: Build
FROM node:22-alpine AS build

WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .

# Stage2: Production (Distroless)
FROM gcr.io/distroless/nodejs22-debian12

WORKDIR /app
COPY --from=build /app .

EXPOSE 3004

CMD ["index2.js"]

In this example, the final image only contains the static build files, eliminating development dependencies.

Size comparison after using Multi-staging

As shown in the given image, a normal Dockerfile results in the Docker image 'kidneys' occupying 1.1 GB of space. In contrast, using multi-stage builds and distroless images reduces the size of the final Docker image 'kidneysmulti' to just 147 MB.

Distroless Images: Minimalistic Docker Images

Distroless images strip off everything but the application and its runtime dependencies. This results in smaller attack surface and reduced image size. You can use the distroless image used in the above code example for building your Node.js docker images.

Combining the Best of Both Worlds

By leveraging multi-stage builds to compile your application and distroless images for the final runtime, you can create highly optimized Docker images that are both small and secure.

Conclusion

Reducing Docker image sizes is important for optimizing performance, reducing build times and minimizing security risks. By using multistage builds, we can efficiently separate build environments from production, significantly shrinking the final image size. Furthermore, distroless images offer a minimalistic and secure approach by containing only necessary dependencies for the application to run. Combining both these techniques enables developers to build efficient, lightweight, and secure Docker containers. I hope this guide helps you create more optimized Docker images. Feel free to check out the complete code in my GitHub repository and share your thoughts in the comments!

0
Subscribe to my newsletter

Read articles from Avirup Ghosal directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Avirup Ghosal
Avirup Ghosal

🚀 Fullstack Developer | DevOps Enthusiast | Creative Builder Hi! I am Avirup Ghosal, a passionate full stack developer and a university student. I have a knack for developing applications using my knowledge on web dev, web3, etc. Currently exploring DevOps and cloud technologies while diving into Web3 and ML on the side. I love tackling complex problems and sharing my learning experiences through code and articles. Let's connect and build something amazing together!