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






Вот пример, в котором сначала к изображению добавляется слой с зависимостями (который создается только при их изменении), а затем слой с полным исходным кодом. Установка 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 и его зависимости от ваших зависимостей. Но, на мой взгляд, это не очень хорошо по двум причинам:
poetry может получить обновление, что нарушит вашу сборку. В этом случае вы можете указать переменную окружения POETRY_VERSION. Установщик будет уважать этоИтак, я использую 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. В docker он нам не нужен. Он уже изолирован. Итак, мы используем настройку poetry config virtualenvs.create false, чтобы выключить его.
Если вы используете один и тот же Dockerfile как для разработки, так и для производства, что и я, вам нужно будет установить разные наборы зависимостей в зависимости от некоторой переменной среды:
poetry install $(test "$YOUR_ENV" == production && echo "--no-dev")
Таким образом, $YOUR_ENV будет контролировать, какой набор зависимостей будет установлен: все (по умолчанию) или производственная версия только с флагом --no-dev.
Вы также можете добавить еще несколько опций для лучшего опыта:
--no-interaction, чтобы не задавать никаких интерактивных вопросов--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
poetry до 1.0@hangtwenty, вы заинтересованы в создании многоступенчатой сборки для wemake-django-template? Это была бы отличная функция, которая уменьшит конечный размер изображения. Если да, напишите мне на github, создав новую проблему, пожалуйста.
Отличная идея! Открыл вопрос. Я завален, но я найду время, чтобы внести свой вклад в ближайшее время
@sobolevn единственное, что беспокоит pip install poetry, это то, что зависимости Poetry могут конфликтовать с зависимостями приложений.
На самом деле поэзия поставляет пакеты, не предназначенные только для Python, что, к сожалению, делает их метод установки curl ненадежным. Я бы установил через pip, пока это не исправлено
poetry config virtualenvs.create false не работает в 1.0.0. Вместо этого используйте RUN POETRY_VIRTUALENVS_CREATE=false poetry install.
У меня все еще работает: travis-ci.com/wemake-services/wemake-django-template/jobs/… Источник: github.com/wemake-services/wemake-django-template/blob/maste r /…
Чтобы легко копировать артефакты многоступенчатой сборки с одного этапа на другой, я полагаюсь на аргумент --user в pip, чтобы я мог просто скопировать /root/.local на свой последний этап. Как бы я поступил так с поэзией?
Если вам нужно штырь поэтической версии в [build-system], не следует ли вам использовать poetry==1.0 вместо использования >=?
Фактически, установка поэзии с помощью pip installделать конфликтует с зависимостями приложений, поскольку зависимости поэзии также имеют свои собственные зависимости. Это полностью под контролем разработчика. При использовании этого метода всегда рекомендуется использовать pip install --ignore-installed. Я тоже не люблю передавать что-то из Интернета прямо в оболочку. Не говоря уже о том, что для этого требуются curl, wget или что-то еще. Но, если вы решили так поступить, есть вариант --version скрипта get-poetry.py.
Этот метод оказался для меня само собой разумеющимся: в моем проекте 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.
@AlexPovel, тогда попробуйте этот метод: github.com/wemake-services/wemake-django-template/blob/maste r /…
Как упоминалось в @AlexPovel, в настоящее время существует проблема, который вызывается в основном из-за того, что зависимости не разделены. Если вы используете dephell или black, и они есть в pyproject.toml, в разделе dev-dependencies все взорвется, если вы установите с --no-dev. Одно из (надеюсь, временное) решение - установить поэзию «официальным» способом.
Это важно для КОПИРОВАНИЯ pyproject.toml вместе с poetry.lock? pyproject.toml также содержит некоторую конфигурацию линтеров, например, и изменения в этом разделе вызывают ненужные промахи кеша. Итак, можно ли КОПИРОВАТЬ только poetry.lock?
Как новичок в поэзии: как мне добраться до такого pyproject.toml с самого начала, если не просто сначала ввести несколько манекенов, как я предлагал в [Поэзии не удалось найти файл pyproject.toml в C:] (stackoverflow.com/a/68995947/11154841)? Это совершенно неправильно? Где я могу взять "типичный" компактный pyproject.toml, который можно использовать повторно?
@ questionto42 вы можете запустить poetry init: python-poetry.org/docs/cli/#init
@sobolevn Да, я это имел в виду. Вы вводите poetry init, а затем вам нужно заполнить некоторые пустышки, что сначала сбивает с толку, так как вы можете подумать, что вместо этого вам нужно добавить необходимые пакеты. Я просто хочу заранее иметь стандартный файл toml с фиктивными значениями, в котором я просто меняю версию Python на нужную.
Чтобы избежать конфликтов зависимостей с самим poetry, вы также можете рассмотреть возможность установки poetry через pipx, который изолирует poetry в его собственном виртуальном окружении: python-poetry.org/docs/#installing-with-pipx
Это минимальная конфигурация, которая мне подходит:
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, который просто создает символическую ссылку. Это означает, что все работает должным образом, когда на последнем этапе поверх него копируются настоящие модули. (Согласно модам, это комментарий, а не редактирование - пожалуйста, попробуйте включить его в сообщение, если вы не согласны.)
Многоступенчатая сборка 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, который ссылается на ваш исходный код, и эта ссылка будет действительна только на этапе сборки.
Обновление: вышла Poetry 1.0.0. Предварительный выпуск больше не требуется для экспортных требований.
Также ознакомьтесь с отличным руководством по упаковке Docker для Python от Itamar Turner-Trauring: pythonspeed.com/docker. Следуя его совету, этот ответ, вероятно, следует обновить, чтобы использовать тонкий образ Debian вместо Alpine.
«Не используйте поэтическую установку для установки вашего кода, потому что она будет выполнять установку с возможностью редактирования». Вы можете отключить это поведение с помощью флага --no-root. См. Закрытую проблему Github здесь.
Вы можете использовать poetry install --no-root вместо экспорта требований для pip install. Но это не помогает с редактируемыми установками. Этот проблема все еще открыт
Это все хорошо, за исключением случаев, когда poetry export -f requirements.txt генерирует недопустимые файлы требований: одни и те же записи дублируются. Похоже, это связано с попыткой поддержки разных версий Python.
Вместо использования virtualenv вы можете использовать установку пользователем (--user), а затем просто скопировать весь $HOME/.local/ в, например,. г. /usr/bin/local/. Есть также варианты пипса --root и --prefix, но кажется, что --root просто не работает (пип 20.2), а --prefix расплывчатый и неясно, что он на самом деле делает. И, как я уже сказал, нет смысла их использовать, так как --user работает безупречно.
Кроме того, для меня идеальным случаем может быть некоторая «предварительная обработка» перед сборкой докеров, например. г. экспорт requirements.txt с использованием локально установленной поэзии. В таком случае мы могли бы даже отказаться от установки поэзии из нашего Dockerfile, что неплохо. К сожалению, это невозможно сделать с помощью самого докера. Однозначно, это можно автоматизировать с помощью, например, г. сценарий оболочки, Makefile или что-то подобное. Однако мне такой подход кажется очень несовместимым со всем процессом сборки.
представил ревизию для замены шага генерации requirements.txt, и этот по-прежнему должен оставаться в нередактируемом состоянии
@ Jeffrey04 Не могли бы вы представить свою версию как отдельный ответ? В будущем я бы предпочел, чтобы вы сначала могли написать комментарий вместо того, чтобы продолжать и вносить существенные изменения в чей-то ответ.
извините, не стесняйтесь вернуться к исходной версии
Обратите внимание, что вы не имеют, чтобы использовать venv для многоступенчатой сборки. Вы также можете установить префикс для установки pip через переменную среды PIP_PREFIX. На базовом этапе отключите virtualenvs, установите префикс в новый каталог (например, /install, сначала mkdir!), А на последнем этапе скопируйте каталог префикса в префикс Python (может быть /usr, может быть /usr/local, может быть что-то еще). Предполагая, что официальные образы докеров Python и /install в качестве префикса, вы должны использовать COPY --from=base /install /usr/local.
Вам не обязательно использовать . /venv/bin/activate, в Dockerfile достаточно использовать ENV PATH = "/venv/bin:${PATH}" и ENV VIRTUAL_ENV = "/venv", что означает, что у вас может быть встроенная точка входа / cmd, и он все равно будет использовать venv.
Мне удалось настроить 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.
Это небольшая редакция ответ предоставлен @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 должна быть тривиальной задачей.
Так что мне действительно нравится этот ответ, но как я могу справиться с зависимостями локальных путей?
что вы имеете в виду под зависимостями локальных путей?
Зависимости пути полезны в настройках монорепозитория, когда у вас есть общие библиотеки где-то еще в вашем репо, см. документы
добавить соответствующие команды COPY перед RUN poetry install или RUN poetry build, я полагаю? мой ответ (а также упомянутые) практически просто реплицирует настройку в контейнере, просто мы явно устанавливаем venv как /venv/, если настройка в контейнере идентична вашей рабочей настройке, все технически должно работать нормально, просто подумайте как бы вы реплицировали установку в другом месте без докера и соответствующим образом скорректировали Dockerfile?
@ Jeffrey04 COPY у меня не работает локальный пакет. Я получаю pip._vendor.pkg_resources.RequirementParseError: Invalid URL: my-package во время команды RUN . /venv/bin/activate && pip install *.whl
Вы проверили, идентичен ли макет файла внутри контейнера?
Если вы копируете venv и запускаете из venv, по какой причине вы также копируете dist и pip install wheel? @ Jeffrey04
хм, мне, вероятно, нужно пересмотреть это, но в настоящее время я не очень много работаю с докером в моей текущей работе (я перестал возиться с ним после того, как тогда он заработал). Если у вас есть время исправить и протестировать, не стесняйтесь редактировать мой ответ (:
Я вижу, что все ответы здесь используют метод 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 Poetry не предназначен для работы без venv. Он буквально использует venv для управления зависимостями. Тем не менее, еще одна причина, по которой люди могут захотеть использовать venv, - это использование контейнеров без дистрибутива. Это делается путем многоступенчатой сборки и перемещения venv (который имеет только необходимые зависимости Python для данного приложения) в выделенный контейнер без беспорядка всей операционной системы. Многие приложения Flask сделаны таким образом. Если, конечно, вам не нравятся контейнеры больших размеров, что делает их не очень портативными. Размер контейнера - это не только вопрос безопасности и поверхности атаки.
@BrandonStivers Если вы хотите написать эссе, сделайте это здесь - stackoverflow.com/questions/68936213/…
Я создал решение, используя пакет блокировки (пакет, который зависит от всех версий в файле блокировки). Это приводит к чистой установке только 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 установит все в пакеты сайтов.
Вот другой подход, который оставляет без изменений 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?
Хороший момент - это не работает в свежем репо. Предполагается, что вы уже настроили Поэзия вручную. Вы можете изменить этот раздел, чтобы скопировать файлы, если они доступны. Я добавил предложение в ответ выше.
Есть два проекта, в которых вы можете увидеть, как это сделать правильно, или вы можете использовать их для создания собственных изображений, поскольку они являются просто базовыми изображениями:
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/
Читатели этого ответа могут позаботьтесь узнать о многоэтапных сборках Docker. Я знаю, что в моем случае многоступенчатые сборки значительно упростили процесс создания базовых и тестовых образов докеров приложений. Также этот пост, который не зависит от поэзии, но показывает причину, по которой мог бы рассматривает возможность продолжения использования virtualenv в докере при выполнении многоэтапных сборок. (Еще не тестировал, я только недавно принял
poetry.)