soof-golan / dockerizing-python

A step-by-step reference on dockerizing a python application
https://www.youtube.com/watch?v=PorXZuDiD0k
MIT License
5 stars 0 forks source link
containers docker python

Dockerizing Python

TL;DR

For the impatient, you can always skip and the take The Red Pill 💊 and skip to the final result of the series.

What is this?

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 ▶️:

Video Thumbnail

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.

Table of Contents

Pre-requisites

To follow along with this series, you will need the following pieces of software installed + a basic understanding of how to use them:

Running The Examples

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

A Starting Point

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.

Step 1 cURL Example

Final Result

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.

Running The Example

docker compose up --build

Summary of all the good stuff we did

Summary of all the stuff we avoided

Things that didn't make the cut