How to Reduce Docker Image Size: Optimization Methods

         


    Software development often involves multiple versions/releases of a service, each with additional dependencies, commands, and configurations. This complexity poses a challenge for Docker image builds, requiring more time and resources.

Instances have been observed where initial application images grew from 350MB to over 1.5 GB due to accumulating dependencies and configurations.

Installing unnecessary libraries can increase the potential security risks by expanding the attack surface.

DevOps engineers should prioritise Docker image optimisation to prevent bloating after application builds or future releases, not only in production but at every stage in the CI/CD process.

Small-sized images are advantageous, especially in container orchestration tools like Kubernetes, as they reduce image transfer and deployment time.

How to Reduce Docker Image Size?

If we take a container image of a typical application, it contains a base image, Dependencies/Files/Configs, and cruft (unwanted software).


The following are the methods by which we can achieve docker image optimization.

  • Using distroless/minimal base images
  • Multistage builds
  • Minimizing the number of layers
  • Understanding caching
  • Using Dockerignore
  • Keeping application data elsewhere

  • Reducing Docker Image Size from 1.13 GB to Minimal 200 MB Range Dockerfile:
    
    # Use the official Node.js image as the base image
    FROM node
    
    # Set the working directory inside the container
    WORKDIR /app
    
    # Copy package.json and package-lock.json to the container
    COPY package*.json ./
    
    # Install dependencies
    RUN npm install
    
    # Copy all application files to the container
    COPY . .
    
    # Expose the port your Node.js app listens on (3000 in this case)
    EXPOSE 3000
    
    # Start the Node.js application
    CMD ["node", "app.js"]
    
    
    Result: 
     
    $ docker images | grep gudditi/node-app
    gudditi/node-app normal_image 9abe4f73d20e   30 seconds ago   1.13GB
     

Method 1: Use Minimal Base Images

Your first focus should be on choosing the right base image with a minimal OS footprint.
node:slim
c2c8591f8fac
linux/amd64
76.27 MB
28a337658177
linux/arm/v7
68.93 MB
710b0331179b
linux/arm64/v8
76.28 MB
d5945d4c7a34
linux/ppc64le
82.43 MB
e898d99d6cba
linux/s390x
74.54 MB


Now Build an image with a minimal base image as node: slim.

    # Use the official Node.js image as the base image
    FROM node:slim
    
    # Set the working directory inside the container
    WORKDIR /app
    
    # Copy package.json and package-lock.json to the container
    COPY package*.json ./
    
    # Install dependencies
    RUN npm install
    
    # Copy all application files to the container
    COPY . .
    
    # Expose the port your Node.js app listens on (3000 in this case)
    EXPOSE 3000
    
    # Start the Node.js application
    CMD ["node", "app.js"]
    
    
    Result: 
     
    $ docker images | grep gudditi/node-app
    gudditi/node-app    normal_image  9abe4f73d20e   30 seconds ago   1.13GB
    gudditi/node-app    latest        f7c43c254bb1   20 minutes ago   282MB
    

Method 2: Use Docker Multistage Builds

The multistage build pattern is evolved from the concept of builder pattern where we use different Dockerfiles for building and packaging the application code. Even though this pattern helps reduce the image size, it puts little overhead when it comes to building pipelines.


    # Use a builder stage with the full Node.js image for building the application
    FROM node:slim as builder

    WORKDIR /app

    COPY package*.json ./

    RUN npm install

    COPY . .

    # Use a slim Node.js image as the final base image
    FROM node:slim

    WORKDIR /app

    # Copy only the necessary files from the builder stage
    COPY --from=builder /app ./

    EXPOSE 3000

    CMD ["node", "app.js"]

    Result: 
     
    $ docker images | grep gudditi/node-app
    gudditi/node-app   minimal_image       518dcc04fb80   14 seconds ago   261MB
    gudditi/node-app   normal_image        9abe4f73d20e   22 minutes ago   1.13GB
    gudditi/node-app   latest              f7c43c254bb1   42 minutes ago   282MB
    


Also, If you follow all the standard container best practices, you can reduce the docker image size to have lightweight image deployments.

Comments

Popular posts from this blog

Remote Friendly Companies

GitHub Actions: A Comprehensive Guide to Automation from Scratch

Introduction to Istio, Kiali, Jaeger, Grafana, and Prometheus