Skip to main content

Learn with Gurpreet

Every space has a story

How to Shrink Docker Images from Gigabytes to Megabytes

#Tech

As developers, we often focus on building and shipping features. However, the efficiency of our delivery pipeline is just as important. One key aspect of this is the size of our Docker images. Large images can lead to slower deployments, increased storage costs, and potential security vulnerabilities. This guide will walk you through several practical steps to significantly reduce the size of your Docker images. It's possible to take a very large image, for example 1.2 GB, and shrink it down to a mere 10 MB.

Why Bother with Image Optimization?

You might wonder why you should care about the size of your Docker images. Here are a few compelling reasons:

Tip 1: Choose a Minimal Base Image

The foundation of your Docker image is the base image. Starting with a large base image is like building a house on a massive, unnecessary foundation.

For example, a standard node:latest image can be over 1 GB. A much better alternative is to use an Alpine Linux based image, such as node:alpine. Alpine is a lightweight Linux distribution designed for security and resource efficiency.

Example Dockerfile (Before):

# Dockerfile

FROM node:latest
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]

Example Dockerfile (After):

# Dockerfile

FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]

For even more aggressive optimization, consider using "distroless" images from Google. These images contain only your application and its runtime dependencies, without a package manager, shell, or other programs you would expect to find in a standard Linux distribution.

Tip 2: Leverage Layer Caching

Docker builds images in layers. Each instruction in your Dockerfile creates a new layer. Docker can cache these layers and reuse them in subsequent builds if the files and instructions have not changed. To take advantage of this, structure your Dockerfile to copy over files that change less frequently first.

For a Node.js application, the package.json and package-lock.json files change less often than your source code. By copying them first and installing dependencies, you can avoid reinstalling dependencies every time you change your code.

Example Dockerfile:

# Dockerfile

FROM node:alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]

Tip 3: Use a .dockerignore File

The Docker build context includes all the files in the directory where you run the docker build command. To avoid sending unnecessary files to the Docker daemon, use a .dockerignore file. This is similar to a .gitignore file and tells Docker which files and directories to exclude.

Example .dockerignore:

# .dockerignore

node_modules
npm-debug.log
.env

Tip 4: Combine RUN Commands

Each RUN command in a Dockerfile creates a new layer. Even if you remove files in a later RUN command, those files still exist in the previous layer, and the image size will not decrease. To avoid this, combine multiple RUN commands into a single command using the && operator.

Example Dockerfile (Before):

# Dockerfile

RUN apt-get update
RUN apt-get install -y some-package
RUN rm -rf /var/lib/apt/lists/*

Example Dockerfile (After):

# Dockerfile

RUN apt-get update && \
    apt-get install -y some-package && \
    rm -rf /var/lib/apt/lists/*

Tip 5: Implement Multi Stage Builds

Multi stage builds are a powerful feature for creating small, secure images. The idea is to use one stage for building and compiling your application, and a second, much smaller stage for the final runtime environment.

For a React application, you can use a node image to build the static files, and then copy those files into a lightweight nginx image to serve them.

Example Dockerfile:

# Dockerfile

# Build stage
FROM node:alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Tools for Optimization

Here are a couple of tools that can help you analyze and optimize your Docker images:

By following these tips and using these tools, you can significantly reduce the size of your Docker images, leading to a more efficient and secure development and deployment process.

:wq