Интеграция Python Poetry с Docker

Можете ли вы дать мне пример Dockerfile, в котором я могу установить все необходимые мне пакеты от Стихи и pyproject.toml в мой образ / контейнер из Docker?

15 ответов

Есть несколько вещей, которые следует иметь в виду при использовании poetry вместе с docker,

Монтаж

Официальный способ установки poetry через:

curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

Этот способ позволяет poetry и его зависимости должны быть изолированы от ваших зависимостей. Но, на мой взгляд, это не очень хорошая вещь по двум причинам:

  1. poetry версия может получить обновление, и это сломает вашу сборку. В этом случае вы можете указать POETRY_VERSION переменная окружения. Установщик будет уважать это
  2. Мне не нравится идея передавать вещи из Интернета в мои контейнеры без какой-либо защиты от возможных изменений файлов

Итак, я использую pip install 'poetry==$POETRY_VERSION', Как видите, я все же рекомендую прикрепить вашу версию.

Кроме того, прикрепите эту версию в свой pyproject.toml также:

[build-system]
# Should be the same as `$POETRY_VERSION`:
requires = ["poetry==0.12.11"]
build-backend = "poetry.masonry.api"

Это защитит вас от несоответствия версий между вашим локальным и docker сред.

Кэширование зависимостей

Мы хотим кэшировать наши требования и переустанавливать их только тогда, когда pyproject.toml или же poetry.lock файлы меняются. В противном случае сборка будет медленной. Для достижения рабочего уровня кэша мы должны поставить:

COPY poetry.lock pyproject.toml /code/

После poetry установлен, но перед добавлением любых других файлов.

Virtualenv

Следующее, что нужно иметь в виду, это virtualenv создание. Нам это не нужно в docker, Он уже изолирован. Итак, мы используем poetry config settings.virtualenvs.create false установка, чтобы выключить его.

Развитие против производства

Если вы используете тот же Dockerfile как для разработки, так и для производства, как и я, вам необходимо установить различные наборы зависимостей на основе некоторой переменной среды:

poetry install $(test "$YOUR_ENV" == production && echo "--no-dev")

Сюда $YOUR_ENV будет контролировать, какой набор зависимостей будет установлен: все (по умолчанию) или только производство с --no-dev флаг.

Вы также можете добавить еще несколько вариантов для лучшего опыта:

  1. --no-interaction не задавать никаких интерактивных вопросов
  2. --no-ansi флаг, чтобы сделать ваш вывод более логичным

Результат

В итоге вы получите нечто похожее на:

FROM python:3.6.6-alpine3.7

ARG YOUR_ENV

ENV YOUR_ENV=${YOUR_ENV} \
  PYTHONFAULTHANDLER=1 \
  PYTHONUNBUFFERED=1 \
  PYTHONHASHSEED=random \
  PIP_NO_CACHE_DIR=off \
  PIP_DISABLE_PIP_VERSION_CHECK=on \
  PIP_DEFAULT_TIMEOUT=100 \
  POETRY_VERSION=0.12.11

# System deps:
RUN pip install "poetry==$POETRY_VERSION"

# Copy only requirements to cache them in docker layer
WORKDIR /code
COPY poetry.lock pyproject.toml /code/

# Project initialization:
RUN poetry config settings.virtualenvs.create false \
  && poetry install $(test "$YOUR_ENV" == production && echo "--no-dev") --no-interaction --no-ansi

# Creating folders, and files for a project:
COPY . /code

Вы можете найти полностью работающий реальный пример здесь: wemake-django-template

Многоступенчатая сборка Docker с помощью Poetry и venv

Не отключайте создание virtualenv. Virtualenvs служат определенной цели в сборках Docker, потому что они предоставляют элегантный способ использования многоэтапных сборок. Короче говоря, на этапе сборки все устанавливается в virtualenv, а на последнем этапе просто копируется virtualenv в небольшой образ.

Использовать poetry exportи сначала установите закрепленные требования, прежде чем копировать код. Это позволит вам использовать кеш сборки Docker и никогда не переустанавливать зависимости только потому, что вы изменили строку в своем коде.

Не использовать poetry installдля установки вашего кода, потому что он выполнит редактируемую установку. Вместо этого используйтеpoetry build, чтобы построить колесо, а затем установить его в свой virtualenv. (Благодаря PEP 517 весь этот процесс также можно было выполнить с помощью простогоpip install ., но из-за изоляции сборки вам придется установить еще одну копию Poetry.)

Вот пример файла Dockerfile, устанавливающего приложение Flask в образ Alpine, с зависимостью от Postgres. В этом примере используется сценарий точки входа для активации файла virtualenv. Но в целом без сценария точки входа все должно быть в порядке, потому что вы можете просто сослаться на двоичный файл Python в/venv/bin/python в вашем CMD инструкция.

Dockerfile

FROM python:3.7.6-alpine3.11 as base

ENV PYTHONFAULTHANDLER=1 \
    PYTHONHASHSEED=random \
    PYTHONUNBUFFERED=1

WORKDIR /app

FROM base as builder

ENV PIP_DEFAULT_TIMEOUT=100 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1 \
    POETRY_VERSION=1.0.5

RUN apk add --no-cache gcc libffi-dev musl-dev postgresql-dev
RUN pip install "poetry==$POETRY_VERSION"
RUN python -m venv /venv

COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt | /venv/bin/pip install -r /dev/stdin

COPY . .
RUN poetry build && /venv/bin/pip install dist/*.whl

FROM base as final

RUN apk add --no-cache libffi libpq
COPY --from=builder /venv /venv
COPY docker-entrypoint.sh wsgi.py ./
CMD ["./docker-entrypoint.sh"]

docker-entrypoint.sh

#!/bin/sh

set -e

. /venv/bin/activate

while ! flask db upgrade
do
     echo "Retry..."
     sleep 1
done

exec gunicorn --bind 0.0.0.0:5000 --forwarded-allow-ips='*' wsgi:app

wsgi.py

import your_app

app = your_app.create_app()

Это небольшая редакция ответа @Claudio, в котором используется новый poetry install --no-rootфункция, описанная @sobolevn в его ответе.

Чтобы заставить поэзию устанавливать зависимости в конкретную виртуальную среду, нужно сначала включить ее.

. /path/to/virtualenv/bin/activate && poetry install

Поэтому добавляя их в ответ @Claudio, мы имеем

FROM python:3.9-slim as base

ENV PYTHONFAULTHANDLER=1 \
    PYTHONHASHSEED=random \
    PYTHONUNBUFFERED=1

RUN apt-get update && apt-get install -y gcc libffi-dev g++
WORKDIR /app

FROM base as builder

ENV PIP_DEFAULT_TIMEOUT=100 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1 \
    POETRY_VERSION=1.1.3

RUN pip install "poetry==$POETRY_VERSION"
RUN python -m venv /venv

COPY pyproject.toml poetry.lock ./
RUN . /venv/bin/activate && poetry install --no-dev --no-root

COPY . .
RUN . /venv/bin/activate && poetry build

FROM base as final

COPY --from=builder /venv /venv
COPY --from=builder /app/dist .
COPY docker-entrypoint.sh ./

RUN . /venv/bin/activate && pip install *.whl
CMD ["./docker-entrypoint.sh"]

Если вам нужно использовать это для целей разработки, вы добавляете или удаляете --no-dev заменив эту строку

RUN . /venv/bin/activate && poetry install --no-dev --no-root

к чему-то вроде этого, как показано в ответе @sobolevn

RUN . /venv/bin/activate && poetry install --no-root $(test "$YOUR_ENV" == production && echo "--no-dev")

после добавления соответствующего объявления переменной среды.

В этом примере в качестве основы используется debian-slim, однако адаптация его к образу на основе alpine должна быть тривиальной задачей.

TL;DR

Я смог настроить poetry для Django проект с использованием postgres. Проведя небольшое исследование, я пришел к следующемуDockerfile:

FROM python:slim

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1

# Install and setup poetry
RUN pip install -U pip \
    && apt-get update \
    && apt install -y curl netcat \
    && curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
ENV PATH="${PATH}:/root/.poetry/bin"

WORKDIR /usr/src/app
COPY . .
RUN poetry config virtualenvs.create false \
  && poetry install --no-interaction --no-ansi

# run entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

Это содержание entrypoint.sh:

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."

    while ! nc -z $SQL_HOST $SQL_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

python manage.py migrate

exec "$@"

Детальное объяснение

Некоторые моменты, на которые следует обратить внимание:

  • Я решил использовать slim вместо того alpine как тег для python изображение, потому что хотя alpineПредполагается, что образы уменьшают размер образов Docker и ускоряют сборку, с Python вы можете фактически получить изображение немного большего размера, а создание этого требует времени (подробнее читайте в этой статье).

  • При использовании этой конфигурации контейнеры создаются быстрее, чем при использовании образа alpine, поскольку мне не нужно добавлять дополнительные пакеты для правильной установки пакетов Python.

  • Я устанавливаю poetryпрямо с URL-адреса, указанного в документации. Мне известны предупреждения, предоставленныеsobolevn. Однако я считаю, что в долгосрочной перспективе лучше использовать последнюю версиюpoetry по умолчанию, чем полагаться на переменную среды, которую я должен периодически обновлять.

  • Обновление переменной среды PATHявляется решающим. В противном случае вы получите сообщение о том, что стихи не найдены.

  • Зависимости устанавливаются непосредственно в интерпретаторе python контейнера. Это не создаетpoetry для создания виртуальной среды перед установкой зависимостей.

Если вам нужен alpine версия этого Dockerfile:

FROM python:alpine

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1

# Install dev dependencies
RUN apk update \
    && apk add curl postgresql-dev gcc python3-dev musl-dev openssl-dev libffi-dev

# Install poetry
RUN pip install -U pip \
    && curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
ENV PATH="${PATH}:/root/.poetry/bin"

WORKDIR /usr/src/app
COPY . .
RUN poetry config virtualenvs.create false \
  && poetry install --no-interaction --no-ansi

# run entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

Обратите внимание, что alpine версия требует некоторых зависимостей postgresql-dev gcc python3-dev musl-dev openssl-dev libffi-dev работать правильно.

Это минимальная конфигурация, которая работает для меня:

FROM python:3.7

ENV PIP_DISABLE_PIP_VERSION_CHECK=on

RUN pip install poetry

WORKDIR /app
COPY poetry.lock pyproject.toml /app/

RUN poetry config settings.virtualenvs.create false
RUN poetry install --no-interaction

COPY . /app

Обратите внимание, что это так же безопасно, как конфигурация @sobolevn.

В качестве мелочи добавлю, что если редактируемые установки будут возможны для проектов pyproject.toml, такой конфигурации будет достаточно:

FROM python:3.7

ENV PIP_DISABLE_PIP_VERSION_CHECK=on

WORKDIR /app
COPY poetry.lock pyproject.toml /app/

RUN pip install -e .

COPY . /app

Используйте многоэтапную сборку докера и тонкий образ Python, экспортируйте поэтическую блокировку в файл requirements.txt, а затем установите через pip внутри virtualenv.

Он имеет наименьший размер , не требует поэзии во время выполнения изображения, закрепляет версии всего.

      FROM python:3.9.7 as base
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app

FROM base as poetry
RUN pip install poetry==1.1.12
COPY poetry.lock pyproject.toml /app/
RUN poetry export -o requirements.txt

FROM base as build
COPY --from=poetry /app/requirements.txt /tmp/requirements.txt
RUN python -m venv .venv && \
    .venv/bin/pip install 'wheel==0.36.2' && \
    .venv/bin/pip install -r /tmp/requirements.txt

FROM python:3.9.7-slim as runtime
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app
ENV PATH=/app/.venv/bin:$PATH
COPY --from=build /app/.venv /app/.venv
COPY . /app

Вот раздетый пример, где сначала к изображению добавляется слой с зависимостями (который создается только при их изменении), а затем слой с полным исходным кодом. настройка poetry установить в глобальном site-packages оставляет артефакт конфигурации, который также можно удалить.

FROM python:alpine

WORKDIR /app

COPY poetry.lock pyproject.toml ./
RUN pip install --no-cache-dir --upgrade pip \
 && pip install --no-cache-dir poetry \
 \
 && poetry config settings.virtualenvs.create false \
 && poetry install --no-dev \
 \
 && pip uninstall --yes poetry \

COPY . ./

Мой Dockerfile основан на ответе @lmiguelvargasf . Обратитесь к его сообщению для более подробного объяснения. Единственные существенные изменения, которые у меня есть, следующие:

  • Сейчас я использую последний официальный установщик install-poetry.pyвместо устаревшего get-poetry.pyкак рекомендовано в их официальной документации . Я также устанавливаю определенную версию, используя --versionфлаг, но вы также можете использовать переменную среды POETRY_VERSION. Больше информации в их официальных документах!

  • В PATHя использую это /root/.local/bin:$PATHвместо ${PATH}:/root/.poetry/binиз Dockerfile OP

      FROM python:3.10.4-slim-buster

ENV PYTHONDONTWRITEBYTECODE 1 \
    PYTHONUNBUFFERED 1

RUN apt-get update \
    && apt-get install curl -y \
    && curl -sSL https://install.python-poetry.org | python - --version 1.1.13

ENV PATH="/root/.local/bin:$PATH"

WORKDIR /usr/app

COPY pyproject.toml poetry.lock ./

RUN poetry config virtualenvs.create false \
    && poetry install --no-dev --no-interaction --no-ansi

COPY ./src ./

EXPOSE 5000

CMD [ "poetry", "run", "gunicorn", "-b", "0.0.0.0:5000", "test_poetry.app:create_app()" ]

Я создал решение, используя пакет блокировки (пакет, который зависит от всех версий в файле блокировки). Это приводит к чистой установке только pip без файлов требований.

Шаги: соберите пакет, соберите пакет блокировки, скопируйте оба колеса в свой контейнер, установите оба колеса с помощью pip.

Установка это: poetry add --dev poetry-lock-package

Шаги за пределами сборки докера:

      poetry build
poetry run poetry-lock-package --build

Тогда твой Dockerfile должен содержать:

      FROM python:3-slim

COPY dist/*.whl /

RUN pip install --no-cache-dir /*.whl \
    && rm -rf /*.whl

CMD ["python", "-m", "entry_module"]

Есть два проекта, в которых вы можете увидеть, как это сделать правильно, или вы можете использовать их для создания собственных изображений, поскольку они являются просто базовыми изображениями:

Dockerfile базового образа: https://github.com/max-pfeiffer/uvicorn-poetry/blob/main/build/Dockerfile

      ARG OFFICIAL_PYTHON_IMAGE
FROM ${OFFICIAL_PYTHON_IMAGE}

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100 \
    POETRY_VERSION=1.1.11 \
    POETRY_HOME="/opt/poetry" \
    POETRY_VIRTUALENVS_IN_PROJECT=true \
    PYTHONPATH=/application_root \
    VIRTUAL_ENVIRONMENT_PATH="/application_root/.venv"

ENV PATH="$POETRY_HOME/bin:$VIRTUAL_ENVIRONMENT_PATH/bin:$PATH"

# https://python-poetry.org/docs/#osx--linux--bashonwindows-install-instructions
RUN apt-get update \
    && apt-get install --no-install-recommends -y \
        build-essential \
        curl \
    && curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python - \
    && apt-get purge --auto-remove -y \
      build-essential \
      curl

COPY ./scripts/start_uvicorn.sh /application_server/
RUN chmod +x /application_server/start_uvicorn.sh

COPY ./scripts/pytest_entrypoint.sh ./scripts/black_entrypoint.sh /entrypoints/
RUN chmod +x /entrypoints/pytest_entrypoint.sh
RUN chmod +x /entrypoints/black_entrypoint.sh

EXPOSE 80

CMD ["/application_server/start_uvicorn.sh"]

Dockerfile примера образа проекта: https://github.com/max-pfeiffer/uvicorn-poetry/blob/main/examples/fast_api_multistage_build/Dockerfile

      ARG BASE_IMAGE_NAME_AND_TAG=pfeiffermax/uvicorn-poetry:1.0.1-python3.9.8-slim-bullseye
FROM ${BASE_IMAGE_NAME_AND_TAG} as base-image

WORKDIR /application_root

# install [tool.poetry.dependencies]
# this will install virtual environment into /.venv because of POETRY_VIRTUALENVS_IN_PROJECT=true
# see: https://python-poetry.org/docs/configuration/#virtualenvsin-project
COPY ./poetry.lock ./pyproject.toml /application_root/
RUN poetry install --no-interaction --no-root --no-dev

FROM base-image as test-base-image
ENV LOG_LEVEL="debug"

COPY --from=base-image $VIRTUAL_ENVIRONMENT_PATH $VIRTUAL_ENVIRONMENT_PATH

# install [tool.poetry.dev-dependencies]
RUN poetry install --no-interaction --no-root

COPY /app /application_root/app/
COPY /tests /application_root/tests/

# image for running pep8 checks
FROM test-base-image as black-test-image

ENTRYPOINT /entrypoints/black_entrypoint.sh $0 $@

CMD ["--target-version py39", "--check", " --line-length 80", "app"]

# image for running unit tests
FROM test-base-image as unit-test-image

ENTRYPOINT /entrypoints/pytest_entrypoint.sh $0 $@

# You need to use pytest-cov as pytest plugin. Makes life very simple.
# tests directory is configured in pyproject.toml
# https://github.com/pytest-dev/pytest-cov
CMD ["--cov=app", "--cov-report=xml:/test_coverage_reports/unit_tests_coverage.xml"]

FROM base-image as development-image
ENV RELOAD="true" \
    LOG_LEVEL="debug"

COPY --from=base-image $VIRTUAL_ENVIRONMENT_PATH $VIRTUAL_ENVIRONMENT_PATH

# install [tool.poetry.dev-dependencies]
RUN poetry install --no-interaction --no-root

COPY . /application_root/

FROM base-image as production-image

COPY --from=base-image $VIRTUAL_ENVIRONMENT_PATH $VIRTUAL_ENVIRONMENT_PATH

# This RUN statement fixes an issue while running the tests with GitHub Actions.
# Tests work reliable locally on my machine or running GitHub Actions using act.
# There is a bug with multistage builds in GitHub Actions which I can also reliable reproduce
# see: https://github.com/moby/moby/issues/37965
# Will also check if I can fix that annoying issue with some tweaks to docker build args
# see: https://gist.github.com/UrsaDK/f90c9632997a70cfe2a6df2797731ac8
RUN true

COPY /app /application_root/app/

Я вижу, что все ответы здесь используют метод pip для установки Poetry, чтобы избежать проблем с версией. Официальный способ установки поэзии - чтение переменной env POETRY_VERSION, если она определена для установки наиболее подходящей версии.

Существует проблема в GitHub здесь , и я думаю , что решение от этого билета довольно интересно:

      # `python-base` sets up all our shared environment variables
FROM python:3.8.1-slim as python-base

    # python
ENV PYTHONUNBUFFERED=1 \
    # prevents python creating .pyc files
    PYTHONDONTWRITEBYTECODE=1 \
    \
    # pip
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100 \
    \
    # poetry
    # https://python-poetry.org/docs/configuration/#using-environment-variables
    POETRY_VERSION=1.0.3 \
    # 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` stage is 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
RUN curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

# 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 poetry install --no-dev


# `development` image is 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 poetry install

# will become mountpoint of our code
WORKDIR /app

EXPOSE 8000
CMD ["uvicorn", "--reload", "main:app"]


# `production` 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"]

Вот другой подход, который оставляет Поэзию нетронутой, поэтому вы все еще можете использовать poetry addи т. д. Это хорошо, если вы используете контейнер разработки VS Code.

Короче говоря, установите Poetry, позвольте Poetry создать виртуальную среду, а затем входите в виртуальную среду каждый раз, когда вы запускаете новую оболочку, изменяя .bashrc.

      FROM ubuntu:20.04

RUN apt-get update && apt-get install -y python3 python3-pip curl

# Use Python 3 for `python`, `pip`
RUN    update-alternatives --install /usr/bin/python  python  /usr/bin/python3 1 \
    && update-alternatives --install /usr/bin/pip     pip     /usr/bin/pip3    1

# Install Poetry
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python3 -
ENV PATH "$PATH:/root/.local/bin/"

# Install Poetry packages (maybe remove the poetry.lock line if you don't want/have a lock file)
COPY pyproject.toml ./
COPY poetry.lock ./
RUN poetry install --no-interaction

# Provide a known path for the virtual environment by creating a symlink
RUN ln -s $(poetry env info --path) /var/my-venv

# Clean up project files. You can add them with a Docker mount later.
RUN rm pyproject.toml poetry.lock

# Hide virtual env prompt
ENV VIRTUAL_ENV_DISABLE_PROMPT 1

# Start virtual env when bash starts
RUN echo 'source /var/my-venv/bin/activate' >> ~/.bashrc

Напоминаем, что нет необходимости избегать использования virtualenv. Это не влияет на производительность , а Poetry не предназначен для работы без них.

Другие ответы были хорошими, но мне пришлось внести некоторые изменения, исходя из следующих требований:

  1. Мне нужно было маленькое изображение, и я решил использовать Alpine.
  2. Я хотел быть уверенным, что окончательный образ не будет запущен от имени пользователя root.
  3. Я был особенно сосредоточен на возможности запустить сценарий Poetry от своего имени.

Например, если у меня есть этот скрипт вpyproject.toml:

      ...
[tool.poetry.scripts]
my_tool = "my_tool.cli.cli:start"
...

Тогда я хотелmy_tool(CLI), чтобы быть моим DockerfileENTRYPOINTчтобы аргументы, предоставленные командами контейнера, были аргументами моего CLI. Это решение выполнило именно то, что я искал:

      # Stage - base
FROM python:3.11-alpine3.18 as base

ENV PYTHONFAULTHANDLER=1 \
    PYTHONHASHSEED=random \
    PYTHONUNBUFFERED=1

WORKDIR /app

# Stage - builder
FROM python:3.11-alpine3.18 as builder

ENV PIP_DEFAULT_TIMEOUT=100 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    POETRY_VERSION=1.7.0

RUN pip install poetry==$POETRY_VERSION

WORKDIR /app

RUN python -m venv /venv

COPY pyproject.toml poetry.lock ./
RUN . /venv/bin/activate && poetry install --no-dev --no-root

COPY . .
RUN . /venv/bin/activate && poetry build

# Stage - release
FROM base as release

# install sudo as root
RUN apk add --update sudo

# add new user
ENV USER=appuser
RUN adduser -D $USER \
        && echo "$USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER \
        && chmod 0440 /etc/sudoers.d/$USER

ENV PATH="/venv/bin:$PATH"

COPY --from=builder /venv /venv
COPY --from=builder /app/dist .
RUN chown -hR $USER /venv

RUN . /venv/bin/activate && pip install *.whl

USER $USER

ENTRYPOINT ["my_cli"]

Dockerfile для моих приложений Python выглядит так:

      FROM python:3.10-alpine
RUN apk update && apk upgrade
RUN pip install -U pip poetry==1.1.13
WORKDIR /app
COPY . .
RUN poetry export --without-hashes --format=requirements.txt > requirements.txt
RUN pip install -r requirements.txt
EXPOSE 8000
ENTRYPOINT [ "python" ]
CMD ["main.py"]

построить образ без питона-поэзии

      FROM abersh/no-pypoetry as requirements

FROM python:3.7

# ... yourself commands

COPY --from=requirements /src/requirements.txt .

RUN pip install -r requirements.txt

# ... yourself commands
Другие вопросы по тегам