Explain Codes LogoExplain Codes Logo

Integrating Python Poetry with Docker

python
virtual-environments
docker
poetry
Nikita BarsukovbyNikita Barsukov·Oct 6, 2024
TLDR

Poetry and Docker harmonize beautifully with the use of multi-stage build, creating a slim image. The builder stage deals with dependencies declared in pyproject.toml and poetry.lock, thus eliminating the necessity for Poetry in the final image.

Slice of the action:

# Python, meet Poetry. Poetry, meet Python. FROM python:3.8 as builder WORKDIR /app RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - COPY pyproject.toml poetry.lock ./ RUN poetry install --no-dev // Hold on, no dev dependencies in the dinner party! # Last call for Python, no room for Poetry! FROM python:3.8-slim WORKDIR /app COPY --from=builder /app ./ CMD ["python", "your_app.py"] // Replace with your app's main entrance!

While the builder stage handles the installations, the slim final image consists only of necessary bits and bobs, leaving it svelter. Don't forget to replace "your_app.py" with the name of your primary execution script.

Pro tips for smooth integration

Environment Variables: Set them once for the whole ride

Environment variables go a lengthy distance in tailoring Dockerfile's behaviour to best suit your app:

ENV POETRY_VERSION=1.1.4 PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
  • Specifying POETRY_VERSION ensures consistent trips by keeping Poetry's version steady.
  • PYTHONUNBUFFERED set to 1 prevents Python from buffering the std out . Because who likes buffering?
  • PYTHONDONTWRITEBYTECODE set to 1 stops Python from creating .pyc files. Let's spare some space in the luggage!

Efficient Caching: Because patience is overrated!

Copy poetry.lock and pyproject.toml before anything else, and Docker's cache would work wonders:

COPY poetry.lock pyproject.toml ./

Efficient caching does the magic of ensuring install layer only rebuilt when these specific files are updated. Thus, you get to enjoy faster and more efficient builds.

Development and Production: It's not always black or white

Use an ARG switch to toggle installing dev dependencies like a Rockstar:

ARG INSTALL_DEV=false RUN if [ "$INSTALL_DEV" = "true" ] ; then poetry install ; else poetry install --no-dev ; fi

Using the --build-arg INSTALL_DEV=true override, the CI environment too can bask in this glory.

Application serving: Give Gunicorn a chance

Serve your application smoothly within the Docker container by giving Gunicorn a shot:

CMD ["gunicorn", "-w 4", "your_app:app"]

Incorporate app, your app factory within your_app.py to bring together Docker's robust container hosting with Gunicorn's flexible serving capabilities.

Virtual environments: Bonus points for isolation

Dependencies: To mingle or not!

Leverage Poetry's feature to create virtual environments breathing in isolated dependencies:

source /path/to/virtualenv/bin/activate

Build Isolation: Say yes to good parceling

Build isolation during Docker build ensures dependencies are well-behaved:

RUN poetry install --no-root --isolated

Opt for Alpine: Because light is right

Resource Optimization: Slimmest is fastest

alpine provides a bare-bones base image if you're uncompromising on your diet:

FROM python:3.8-alpine as builder ...

Compilation: Twist in the tale

Binary dependencies would greet you when you opt for alpine, but fear not:

RUN apk add --no-cache gcc musl-dev libffi-dev