6.1 Getting to Know Image Optimization
Docker images, while compact, still take up space. So, reducing their size is super important—it helps boost performance, speeds up loading and deploying containers, and cuts down on storage costs. You can optimize an image by improving the Dockerfile since it can be organized in different ways. In this lecture, we'll go over a few strategies and best practices to create optimized and lightweight Docker images.
Why is it important to reduce Docker image size?
- Deployment speed: Smaller images load faster from the Docker registry and deploy into containers more quickly, which is especially crucial in automated CI/CD systems.
- Efficient resource usage: Lightweight images take up less disk space, save network resources during transfer, and ensure more efficient use of computing power.
- Security: Smaller images typically include fewer unnecessary components, reducing the risk of potential vulnerabilities.
- Simplifying updates: Updating lightweight images is faster and uses fewer resources, accelerating the support process.
6.2 Strategies for Reducing Docker Image Size
1. Using Minimal Base Images
Choosing a base image directly affects the final Docker image size. Using minimal base images like alpine
can significantly shrink the image size.
Example:
Replacing the ubuntu
image with alpine
:
# FROM ubuntu:20.04
FROM alpine:3.12
alpine
is a lightweight Linux distribution that takes up about 5 MB, while the ubuntu
image can take up hundreds of megabytes.
2. Minimizing the Number of Layers
Each instruction in the Dockerfile adds a new layer to the image. Combining multiple commands into one RUN
instruction reduces the number of layers, which helps shrink the total image size.
Example:
Before optimization:
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
RUN rm -rf /var/lib/apt/lists/*
After optimization:
RUN apt-get update && apt-get install -y curl git && rm -rf /var/lib/apt/lists/*
Deleting the package manager cache (rm -rf /var/lib/apt/lists/*)
further reduces the image size by removing temporary files created during the installation.
3. Removing Temporary Files
Deleting temporary files and unnecessary data after installing packages keeps the image clean and lightweight.
Example:
RUN apt-get update && apt-get install -y curl git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
4. Using .dockerignore
The .dockerignore
file helps exclude unnecessary files and directories from the build context, reducing the image size and speeding up the build process.
Example .dockerignore
:
node_modules
dist
*.log
Dockerfile*
.dockerignore
5. Multi-Stage Builds
Multi-stage builds allow you to use multiple intermediate images to create a final lightweight image containing only the necessary files and dependencies.
Example:
# Build stage
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Final stage
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
In this example, the first stage builds the application, and the final stage uses only the build results, reducing the size of the final image.
6. Optimizing Package Installation
Installing only necessary packages and using package manager options for minimal installation help reduce the image size.
Example:
Using the --no-install-recommends
option with apt-get
:
RUN apt-get update && apt-get install -y --no-install-recommends curl git && \
rm -rf /var/lib/apt/lists/*
7. Compressing and Minimizing Data
Using tools for compressing and minimizing data helps shrink the image size.
Example:
Compressing text files and log files:
RUN gzip /path/to/large/file.log
8. Removing Unused Libraries and Dependencies
Removing unused libraries and dependencies after installing the necessary packages keeps the image lightweight.
Example:
For Python applications:
RUN pip install --no-cache-dir -r requirements.txt
6.3 Examples of Optimized Dockerfile
Example 1: Optimized Dockerfile for Node.js
FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
This example uses a multi-stage build. First, the app is built in an intermediate stage, and then only the build results are copied to the final image based on Nginx.
Example 2: Optimized Dockerfile for Python
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
This example uses a lightweight base image python:3.9-slim
. Installing dependencies is placed in a separate step, which allows Docker to use caching if the requirements.txt
file hasn’t changed.
GO TO FULL VERSION