I've created a Python app that connects to the Forem's API to get a list of the articles I wrote on DEV, and it displays the result on a web page built with Flask. The source code is available on a GitLab repository.
To containerize this app with Docker, create a Dockerfile
with the following content:
FROM python:latest
WORKDIR /app
COPY requirements.txt .
RUN pip install --upgrade pip --no-cache-dir
RUN pip install -r requirements.txt --no-cache-dir
COPY . .
EXPOSE 8080
ENTRYPOINT ["gunicorn","--config", "gunicorn_config.py", "app:app"]
Now build the image by running:
$ docker build . -t blog
If you run the following command:
$ docker image ls blog
You'll get the following output:
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest 3debcac78e45 20 minutes ago 1.05GB
The image size is 1.05GB
. How to optimize the Docker image?
There are a few approaches that can be analyzed:
- Use smaller base images
- Multi-stage builds
Through this blog post, you'll learn how to optimize your Docker image through both solutions.
Use Smaller Base Images
Using a smaller base image can help reduce the image size. Replace the python:latest
image with the python:alpine3.19
image:
FROM python:alpine3.19
WORKDIR /app
COPY requirements.txt .
RUN pip install --upgrade pip --no-cache-dir
RUN pip install -r requirements.txt --no-cache-dir
COPY . .
EXPOSE 8080
ENTRYPOINT ["gunicorn","--config", "gunicorn_config.py", "app:app"]
Build the image:
$ docker build . -t blog
Run the following command:
$ docker image ls blog
This is the output you get:
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest 2b3085ad2c5d 19 seconds ago 81.1MB
As you see, the image size was reduced from 1.05GB
to 81.1MB
.
Multi-stage builds
I wrote about how to use multi-stage builds to optimize a containerized Rust app, and as it is explained here, this solution could also work for Python apps.
Create a Dockerfile
as follows, with multi-stage builds and venv:
FROM python:alpine3.19 as builder
ENV PATH="/app/venv/bin:$PATH"
WORKDIR /app
RUN python -m venv /app/venv
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
FROM python:alpine3.19
WORKDIR /app
ENV PATH="/app/venv/bin:$PATH"
COPY . .
COPY --from=builder /app/venv /app/venv
ENTRYPOINT ["gunicorn", "--config", "gunicorn_config.py", "app:app"]
Build the image:
$ docker build . -t blog
Run the following command:
$ docker image ls blog
This is the output you get:
REPOSITORY TAG IMAGE ID CREATED SIZE
blog latest 2b3085ad2c5d 19 seconds ago 76.2MB
The image was reduced a little more, compared to the result obtained while only using a smaller base image.
Conclusion
Through this blog post, you learned how to optimize your containerized Python app, through different solutions, and combining all the practices described here.
Top comments (0)