For the impatient, you can always skip and the take The Red Pill 💊 and skip to the final result of the series.
This repository contains a series of examples on how to Dockerize Python applications. I tried to make each stage "production ready", so you should be able to use any of them as a starting point for your own project.
You can follow along with the video on YouTube ▶️:
In each step, we will add a new feature to our Dockerfile, each addition will trade off somthing for something else. The goal is to end up with a Dockerfile that is both simple, robust and easy to maintain.
To follow along with this series, you will need the following pieces of software installed + a basic understanding of how to use them:
In each folder, you will find a README.md
file that explains the changes made in that step, and a Dockerfile
that
contains the final result of that step. To see the final result of each step in action, you can run:
cd <step-folder>
docker compose up --build
This is our stupidly simple starting point:
FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["gunicorn", "kiss.main:app"]
We'll start with this Dockerfile, and incrementally improve it until we have a production-ready image. I'll see you in Step 1, and we'll build up from there.
Congratulations! You've reached the end of the series. This is our final Dockerfile 🐳:
# Use the official Python image. Beware of -slim or -alpine here!
FROM python:3.11
# Configure Python to behave well inside the container.
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONFAULTHANDLER=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# Set the working directory to /app.
WORKDIR /app
# Copy only the (auto-generated) requirements.txt file
COPY ./requirements.txt ./
# Install dependencies (with caching).
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --require-hashes -r requirements.txt
# Compile "all" Python files in the PYTHONPATH to bytescode (10 levels deep)
RUN python -m compileall $(python -c "import sys; print(' '.join(sys.path), end='')") -r 10
# Copy the rest of the codebase into the image.
COPY . .
# Install the "root" application (with caching).
RUN --mount=type=cache,target=/root/.cache/pip \
pip install . --no-deps
# Compile our own source code
RUN python -m compileall src -r 10
# Start the production server.
CMD ["gunicorn", "dockerizing_python.main:app"]
This file contains all the bells and whistles we've added throughout the series.
docker compose up --build
fastapi
)pytest
)gunicorn
)poetry export
to generate a requirements.txt
file. (
see step-4-nontrivial-improvements)
.dockerignore
. (see
step-5-larger-project)