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

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
144
0
76 748
10

Ответы 10

Вот пример, в котором сначала к изображению добавляется слой с зависимостями (который создается только при их изменении), а затем слой с полным исходным кодом. Установка 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 . ./

При использовании poetry вместе с docker следует помнить о нескольких вещах.

Установка

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

curl -sSL https://raw.githubusercontent.com/python-poetry/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>=1.0"]
build-backend = "poetry.masonry.api"

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

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

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

COPY poetry.lock pyproject.toml /code/

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

Virtualenv

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

Разработка vs Производство

Если вы используете один и тот же 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=1.0.0

# 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 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

Обновление на 2019-12-17

  • Обновите poetry до 1.0

Читатели этого ответа могут позаботьтесь узнать о многоэтапных сборках Docker. Я знаю, что в моем случае многоступенчатые сборки значительно упростили процесс создания базовых и тестовых образов докеров приложений. Также этот пост, который не зависит от поэзии, но показывает причину, по которой мог бы рассматривает возможность продолжения использования virtualenv в докере при выполнении многоэтапных сборок. (Еще не тестировал, я только недавно принял poetry.)

driftcatcher 14.03.2019 01:54

@hangtwenty, вы заинтересованы в создании многоступенчатой ​​сборки для wemake-django-template? Это была бы отличная функция, которая уменьшит конечный размер изображения. Если да, напишите мне на github, создав новую проблему, пожалуйста.

sobolevn 14.03.2019 10:57

Отличная идея! Открыл вопрос. Я завален, но я найду время, чтобы внести свой вклад в ближайшее время

driftcatcher 14.03.2019 23:55

@sobolevn единственное, что беспокоит pip install poetry, это то, что зависимости Poetry могут конфликтовать с зависимостями приложений.

Rob Grant 09.06.2019 15:21

На самом деле поэзия поставляет пакеты, не предназначенные только для Python, что, к сожалению, делает их метод установки curl ненадежным. Я бы установил через pip, пока это не исправлено

aaaaaa 29.09.2019 07:20
poetry config virtualenvs.create false не работает в 1.0.0. Вместо этого используйте RUN POETRY_VIRTUALENVS_CREATE=false poetry install.
JerryDDG 18.12.2019 04:14

У меня все еще работает: travis-ci.com/wemake-services/wemake-django-template/jobs/… Источник: github.com/wemake-services/wemake-django-template/blob/maste‌ r /…

sobolevn 18.12.2019 13:04

Чтобы легко копировать артефакты многоступенчатой ​​сборки с одного этапа на другой, я полагаюсь на аргумент --user в pip, чтобы я мог просто скопировать /root/.local на свой последний этап. Как бы я поступил так с поэзией?

beeb 04.06.2020 19:26

Если вам нужно штырь поэтической версии в [build-system], не следует ли вам использовать poetry==1.0 вместо использования >=?

ewen-lbh 26.07.2020 20:36

Фактически, установка поэзии с помощью pip installделать конфликтует с зависимостями приложений, поскольку зависимости поэзии также имеют свои собственные зависимости. Это полностью под контролем разработчика. При использовании этого метода всегда рекомендуется использовать pip install --ignore-installed. Я тоже не люблю передавать что-то из Интернета прямо в оболочку. Не говоря уже о том, что для этого требуются curl, wget или что-то еще. Но, если вы решили так поступить, есть вариант --version скрипта get-poetry.py.

tosh 28.08.2020 16:13

Этот метод оказался для меня само собой разумеющимся: в моем проекте pyproject.toml у меня все было настроено нормально. Однако pip install poetry (на Python 3.7) устанавливает appdirs как зависимость от poetry, как и предполагалось. Но при работе с config virtualenvs.create false, poetry запускается "на чистом металле", а удаляетappdirs снова (Removing appdirs (1.4.4), при установке нормальных зависимостей проекта нормально). Это потому, что appdirs не был указан в pyproject.toml (а зачем?). Я снова вернулся к использованию виртуальных окружений, так что poetry не удаляет appdirs.

Alex Povel 01.03.2021 12:30

@AlexPovel, тогда попробуйте этот метод: github.com/wemake-services/wemake-django-template/blob/maste‌ r /…

sobolevn 01.03.2021 12:48

Как упоминалось в @AlexPovel, в настоящее время существует проблема, который вызывается в основном из-за того, что зависимости не разделены. Если вы используете dephell или black, и они есть в pyproject.toml, в разделе dev-dependencies все взорвется, если вы установите с --no-dev. Одно из (надеюсь, временное) решение - установить поэзию «официальным» способом.

Adrian Pop 11.05.2021 10:59

Это важно для КОПИРОВАНИЯ pyproject.toml вместе с poetry.lock? pyproject.toml также содержит некоторую конфигурацию линтеров, например, и изменения в этом разделе вызывают ненужные промахи кеша. Итак, можно ли КОПИРОВАТЬ только poetry.lock?

dem1tris 10.06.2021 10:41

Как новичок в поэзии: как мне добраться до такого pyproject.toml с самого начала, если не просто сначала ввести несколько манекенов, как я предлагал в [Поэзии не удалось найти файл pyproject.toml в C:] (stackoverflow.com/a/68995947/11154841)? Это совершенно неправильно? Где я могу взять "типичный" компактный pyproject.toml, который можно использовать повторно?

questionto42 31.08.2021 11:36

@ questionto42 вы можете запустить poetry init: python-poetry.org/docs/cli/#init

sobolevn 01.09.2021 20:41

@sobolevn Да, я это имел в виду. Вы вводите poetry init, а затем вам нужно заполнить некоторые пустышки, что сначала сбивает с толку, так как вы можете подумать, что вместо этого вам нужно добавить необходимые пакеты. Я просто хочу заранее иметь стандартный файл toml с фиктивными значениями, в котором я просто меняю версию Python на нужную.

questionto42 02.09.2021 08:17

Чтобы избежать конфликтов зависимостей с самим poetry, вы также можете рассмотреть возможность установки poetry через pipx, который изолирует poetry в его собственном виртуальном окружении: python-poetry.org/docs/#installing-with-pipx

JTunis 03.12.2021 18:10

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

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 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 mymodule, который вы хотели бы установить - как это делает Poetry по умолчанию, если он его находит - вам необходимо создать такую ​​фиктивную версию, прежде чем запускать поэтическую установку: RUN mkdir /app/mymodule && touch /app/mymodule/__init__.py. Это работает, потому что Poetry устанавливает эти типы модулей с помощью pip -e, который просто создает символическую ссылку. Это означает, что все работает должным образом, когда на последнем этапе поверх него копируются настоящие модули. (Согласно модам, это комментарий, а не редактирование - пожалуйста, попробуйте включить его в сообщение, если вы не согласны.)

Frankie Robertson 23.04.2019 12:37

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

Не отключайте создание virtualenv. Virtualenv служат определенной цели в сборках 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()

@stderr Редактируемая установка на самом деле не устанавливает ваш пакет в виртуальную среду. Он создает файл .egg-link, который ссылается на ваш исходный код, и эта ссылка будет действительна только на этапе сборки.

Claudio 08.12.2019 21:38

Обновление: вышла Poetry 1.0.0. Предварительный выпуск больше не требуется для экспортных требований.

Claudio 13.12.2019 17:19

Также ознакомьтесь с отличным руководством по упаковке Docker для Python от Itamar Turner-Trauring: pythonspeed.com/docker. Следуя его совету, этот ответ, вероятно, следует обновить, чтобы использовать тонкий образ Debian вместо Alpine.

Claudio 04.05.2020 16:19

«Не используйте поэтическую установку для установки вашего кода, потому что она будет выполнять установку с возможностью редактирования». Вы можете отключить это поведение с помощью флага --no-root. См. Закрытую проблему Github здесь.

radzak 05.05.2020 16:36

Вы можете использовать poetry install --no-root вместо экспорта требований для pip install. Но это не помогает с редактируемыми установками. Этот проблема все еще открыт

Claudio 05.05.2020 16:41

Это все хорошо, за исключением случаев, когда poetry export -f requirements.txt генерирует недопустимые файлы требований: одни и те же записи дублируются. Похоже, это связано с попыткой поддержки разных версий Python.

Matthew Schinckel 04.06.2020 09:30

Вместо использования virtualenv вы можете использовать установку пользователем (--user), а затем просто скопировать весь $HOME/.local/ в, например,. г. /usr/bin/local/. Есть также варианты пипса --root и --prefix, но кажется, что --root просто не работает (пип 20.2), а --prefix расплывчатый и неясно, что он на самом деле делает. И, как я уже сказал, нет смысла их использовать, так как --user работает безупречно.

tosh 28.08.2020 16:06

Кроме того, для меня идеальным случаем может быть некоторая «предварительная обработка» перед сборкой докеров, например. г. экспорт requirements.txt с использованием локально установленной поэзии. В таком случае мы могли бы даже отказаться от установки поэзии из нашего Dockerfile, что неплохо. К сожалению, это невозможно сделать с помощью самого докера. Однозначно, это можно автоматизировать с помощью, например, г. сценарий оболочки, Makefile или что-то подобное. Однако мне такой подход кажется очень несовместимым со всем процессом сборки.

tosh 28.08.2020 16:27

представил ревизию для замены шага генерации requirements.txt, и этот по-прежнему должен оставаться в нередактируемом состоянии

Jeffrey04 30.10.2020 15:50

@ Jeffrey04 Не могли бы вы представить свою версию как отдельный ответ? В будущем я бы предпочел, чтобы вы сначала могли написать комментарий вместо того, чтобы продолжать и вносить существенные изменения в чей-то ответ.

Claudio 30.10.2020 21:13

извините, не стесняйтесь вернуться к исходной версии

Jeffrey04 31.10.2020 09:39

Обратите внимание, что вы не имеют, чтобы использовать venv для многоступенчатой ​​сборки. Вы также можете установить префикс для установки pip через переменную среды PIP_PREFIX. На базовом этапе отключите virtualenvs, установите префикс в новый каталог (например, /install, сначала mkdir!), А на последнем этапе скопируйте каталог префикса в префикс Python (может быть /usr, может быть /usr/local, может быть что-то еще). Предполагая, что официальные образы докеров Python и /install в качестве префикса, вы должны использовать COPY --from=base /install /usr/local.

Martijn Pieters 28.04.2021 09:38

Вам не обязательно использовать . /venv/bin/activate, в Dockerfile достаточно использовать ENV PATH = "/venv/bin:${PATH}" и ENV VIRTUAL_ENV = "/venv", что означает, что у вас может быть встроенная точка входа / cmd, и он все равно будет использовать venv.

Duncan 12.07.2021 18:47

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.

Считайте, что в долгосрочной перспективе лучше использовать позднюю версию стихов - Нет, действительно нет. Поскольку серьезное критическое изменение в каком-то новом выпуске Poetry может сломать всю вашу сборку, вам все равно придется изменить ее, чтобы использовать жестко запрограммированную версию выпуска.
OneCricketeer 15.06.2021 08:16

Это небольшая редакция ответ предоставлен @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 должна быть тривиальной задачей.

Так что мне действительно нравится этот ответ, но как я могу справиться с зависимостями локальных путей?

DUWUDA 03.02.2021 08:34

что вы имеете в виду под зависимостями локальных путей?

Jeffrey04 03.02.2021 13:09

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

Luper Rouch 04.02.2021 15:36

добавить соответствующие команды COPY перед RUN poetry install или RUN poetry build, я полагаю? мой ответ (а также упомянутые) практически просто реплицирует настройку в контейнере, просто мы явно устанавливаем venv как /venv/, если настройка в контейнере идентична вашей рабочей настройке, все технически должно работать нормально, просто подумайте как бы вы реплицировали установку в другом месте без докера и соответствующим образом скорректировали Dockerfile?

Jeffrey04 05.02.2021 04:00

@ Jeffrey04 COPY у меня не работает локальный пакет. Я получаю pip._vendor.pkg_resources.RequirementParseError: Invalid URL: my-package во время команды RUN . /venv/bin/activate && pip install *.whl

kellpossible 04.12.2021 21:52

Вы проверили, идентичен ли макет файла внутри контейнера?

Jeffrey04 17.12.2021 06:32

Если вы копируете venv и запускаете из venv, по какой причине вы также копируете dist и pip install wheel? @ Jeffrey04

Zaffer 22.12.2021 12:03

хм, мне, вероятно, нужно пересмотреть это, но в настоящее время я не очень много работаю с докером в моей текущей работе (я перестал возиться с ним после того, как тогда он заработал). Если у вас есть время исправить и протестировать, не стесняйтесь редактировать мой ответ (:

Jeffrey04 23.12.2021 08:29

Я вижу, что все ответы здесь используют метод 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"]

На самом деле вам не нужен venv при запуске кода в контейнере

OneCricketeer 15.06.2021 08:18

@OneCricketeer Poetry не предназначен для работы без venv. Он буквально использует venv для управления зависимостями. Тем не менее, еще одна причина, по которой люди могут захотеть использовать venv, - это использование контейнеров без дистрибутива. Это делается путем многоступенчатой ​​сборки и перемещения venv (который имеет только необходимые зависимости Python для данного приложения) в выделенный контейнер без беспорядка всей операционной системы. Многие приложения Flask сделаны таким образом. Если, конечно, вам не нравятся контейнеры больших размеров, что делает их не очень портативными. Размер контейнера - это не только вопрос безопасности и поверхности атаки.

Brandon Stivers 25.11.2021 22:29

@BrandonStivers Если вы хотите написать эссе, сделайте это здесь - stackoverflow.com/questions/68936213/…

OneCricketeer 02.12.2021 18:25

Я создал решение, используя пакет блокировки (пакет, который зависит от всех версий в файле блокировки). Это приводит к чистой установке только 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"]

идеальное решение. мой исходный комментарий об исходном коде python неверен, pip установит все в пакеты сайтов.

kakarukeys 22.06.2021 06:25

Вот другой подход, который оставляет без изменений Poetry, поэтому вы все равно можете использовать 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 не предназначены для работы без них.

Обновлено: @Davos указывает, что это не сработает, если у вас еще нет файлов pyproject.toml и poetry.lock. Если вам нужно обработать этот случай, вы можете использовать этот обходной путь, который должен работать независимо от того, существуют эти файлы или нет.

COPY pyproject.toml* ./
COPY poetry.lock* ./
RUN poetry init --no-interaction; (exit 0) # Does nothing if pyproject.toml exists
RUN poetry install --no-interaction

Выглядит чисто. Вы копируете pyproject.toml и файл блокировки, вы создали их вручную или вы также используете поэзию на своем хост-компьютере, чтобы сначала создать проект? Если да, то зачем использовать удаленный контейнер с vscode?

Davos 13.12.2021 18:42

Хороший момент - это не работает в свежем репо. Предполагается, что вы уже настроили Поэзия вручную. Вы можете изменить этот раздел, чтобы скопировать файлы, если они доступны. Я добавил предложение в ответ выше.

gbw 14.12.2021 21:36

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

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/

Другие вопросы по теме