Using multistage docker builds with distroless base image for Simple Java and Python Apps!

If you are creating containerized applications with huge image sizes then there will be a high chance that you will be having issues with resource consumption. It is always best practice to keep an eye on the size of the images we are producing!

We can witness it with the example below.

Java Example

// Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

For this simple HelloWorld app, initially, I used Single stage DockerFile

# Use an official Java image as the base image
FROM openjdk:11

# Set the working directory inside the container
WORKDIR /app

# Copy the Java application source code into the container
COPY Main.java .

# Compile the Java code
RUN javac Main.java

# Run the Java application
CMD ["java", "Main"]

We can see the size as 654MB for this simple HelloWorld App

I again tried to build this with a multi-stage docker build along with a distroless base image.

# Build Stage
FROM openjdk:11 AS build
WORKDIR /app
COPY Main.java .
RUN javac Main.java

# Final Stage with Distroless
FROM gcr.io/distroless/java:11
WORKDIR /app
COPY --from=build /app/Main.class .
CMD ["Main"]

As we see size of the image has been reduced to 210 MB

Python example

Here is app.py that prints Hello World!

print("Hello, World!")

Below is the Dockerfile with single stage Docker build

# Use an official Python image as the base image
FROM python:3.9

# Set the working directory inside the container
WORKDIR /app

# Copy the Python application source code into the container
COPY app.py .

# Run the Python application
CMD ["python", "app.py"]

The below example is with a multi-stage docker build using a distroless image and also a snapshot of both of these images.

# Build Stage
FROM python:3.9 AS build
WORKDIR /app
COPY app.py .
RUN pip install pyinstaller
RUN pyinstaller --onefile app.py

# Final Stage with Distroless
FROM gcr.io/distroless/python3
WORKDIR /app
COPY --from=build /app/dist/app .
CMD ["./app"]

As we see above, we can see a noticeable advantage in using multi-stage docker builds with distroless base images.