Skip to content

Instantly share code, notes, and snippets.

@usr-ein
Last active February 8, 2025 02:22
Show Gist options
  • Save usr-ein/c42d98abca3cb4632ab0c2c6aff8c88a to your computer and use it in GitHub Desktop.
Save usr-ein/c42d98abca3cb4632ab0c2c6aff8c88a to your computer and use it in GitHub Desktop.
Optimal multistaged Dockerfile for poetry
# syntax=docker/dockerfile:1
# Keep this syntax directive! It's used to enable Docker BuildKit
# Based on https://github.com/python-poetry/poetry/discussions/1879?sort=top#discussioncomment-216865
# but I try to keep it updated (see history)
################################
# PYTHON-BASE
# Sets up all our shared environment variables
################################
FROM python:3.9-slim as python-base
# python
ENV PYTHONUNBUFFERED=1 \
# prevents python creating .pyc files
PYTHONDONTWRITEBYTECODE=1 \
\
# pip
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
\
# poetry
# https://python-poetry.org/docs/configuration/#using-environment-variables
POETRY_VERSION=1.3.2 \
# make poetry install to this location
POETRY_HOME="/opt/poetry" \
# make poetry create the virtual environment in the project's root
# it gets named `.venv`
POETRY_VIRTUALENVS_IN_PROJECT=true \
# do not ask any interactive question
POETRY_NO_INTERACTION=1 \
\
# paths
# this is where our requirements + virtual environment will live
PYSETUP_PATH="/opt/pysetup" \
VENV_PATH="/opt/pysetup/.venv"
# prepend poetry and venv to path
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"
################################
# BUILDER-BASE
# Used to build deps + create our virtual environment
################################
FROM python-base as builder-base
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
# deps for installing poetry
curl \
# deps for building python deps
build-essential
# install poetry - respects $POETRY_VERSION & $POETRY_HOME
# The --mount will mount the buildx cache directory to where
# Poetry and Pip store their cache so that they can re-use it
RUN --mount=type=cache,target=/root/.cache \
curl -sSL https://install.python-poetry.org | python3 -
# copy project requirement files here to ensure they will be cached.
WORKDIR $PYSETUP_PATH
COPY poetry.lock pyproject.toml ./
# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally
RUN --mount=type=cache,target=/root/.cache \
poetry install --without=dev
################################
# DEVELOPMENT
# Image used during development / testing
################################
FROM python-base as development
ENV FASTAPI_ENV=development
WORKDIR $PYSETUP_PATH
# copy in our built poetry + venv
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
# quicker install as runtime deps are already installed
RUN --mount=type=cache,target=/root/.cache \
poetry install --with=dev
# will become mountpoint of our code
WORKDIR /app
EXPOSE 8000
CMD ["uvicorn", "--reload", "main:app"]
################################
# PRODUCTION
# Final image used for runtime
################################
FROM python-base as production
ENV FASTAPI_ENV=production
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
COPY ./app /app/
WORKDIR /app
CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "main:app"]
@Hossein-Gholami
Copy link

hi @usr-ein thanks for sharing. I wonder if it's possible to reduce the resulting image's size. any idea how?

@GGG1998
Copy link

GGG1998 commented May 29, 2024

Nice image, but I have a question. What is a sense use stage after set ENVs(https://gist.github.com/usr-ein/c42d98abca3cb4632ab0c2c6aff8c88a#file-dockerfile-L47) ? Finally, we will use prod or dev part

@sn0opy
Copy link

sn0opy commented Jun 20, 2024

What's the use of PIP_DISABLE_PIP_VERSION_CHECK and PIP_DEFAULT_TIMEOUT if this is entirely based on Poetry?

@michaeltoohig
Copy link

What's the use of PIP_DISABLE_PIP_VERSION_CHECK and PIP_DEFAULT_TIMEOUT if this is entirely based on Poetry?

@sn0opy Poetry is basically a wrapper around pip.

@ZachHandley
Copy link

Any reason you're still using 1.3.2? Latest release as I'm typing this is 1.8.5 -- that's a pretty big differential

@bpehlivan
Copy link

bpehlivan commented Dec 11, 2024

Any reason you're still using 1.3.2? Latest release as I'm typing this is 1.8.5 -- that's a pretty big differential

@ZachHandley I was also just looking at this and seems like this is a bit behind, it is using python 3.9 as of today there is 3.13 available

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment