将Python诗歌与Docker集成


Answers:


141

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.tomlpoetry.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标志的生产。

您可能还想添加一些其他选项以获得更好的体验:

  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

2
该答案的读者可能会想了解Docker多阶段构建。我知道在我的案例中,多阶段构建大大简化了基础,测试与应用docker镜像的过程。另请参阅本文,该文章不是特定于诗歌的,但显示了进行多阶段构建时可能会考虑继续在docker中使用virtualenv的原因。(尚未进行自我测试,我只是poetry最近才采用。)
漂流者

3
@hangtwenty您是否有兴趣为wemake-django-template贡献多阶段构建?这将是一个很棒的功能,它将减小最终图像的大小。如果是这样,请通过创建新问题在github上给我写一行。
sobolevn

4
@sobolevn唯一担心的pip install poetry是诗歌的依赖项可能与应用程序依赖项发生冲突。
罗布·格兰特

3
poetry config virtualenvs.create false在1.0.0中不起作用。使用RUN POETRY_VIRTUALENVS_CREATE=false poetry install代替。
JerryDDG '19


60

使用Poetry和venv的多阶段Docker构建

不要禁用virtualenv创建。Virtualenvs在Docker构建中有一个用途,因为它们提供了一种优雅的方式来利用多阶段构建。简而言之,您的构建阶段会将所有内容安装到virtualenv中,最后一步只是将virtualenv复制到一个小映像中。

poetry export复制代码之前,请先使用并安装您的固定需求。这将允许您使用Docker构建缓存,而不必仅仅因为更改了代码行而重新安装了依赖项。

不要使用poetry install安装代码,因为它将执行可编辑的安装。而是使用poetry build构建轮子,然后将其通过pip安装到您的virtualenv中。(由于PEP 517,整个过程也可以用一个简单的方法执行pip install .,但是由于构建隔离,您最终将安装另一本《 Poetry》。)

这是一个示例文件,该文件将Flask应用安装到Alpine映像中,并依赖于Postgres。本示例使用入口点脚本来激活virtualenv。但是通常,没有入口点脚本就可以了,因为您可以/venv/bin/pythonCMD指令中简单地引用Python二进制文件。

Docker文件

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()

1
@stderr可编辑的安装实际上并未将您的软件包安装到虚拟环境中。它会创建一个.egg-link文件,该文件链接到您的源代码,并且此链接仅在构建阶段有效。
克劳迪奥

2
更新:诗1.0.0已发布。预发行不再需要导出要求。
克劳迪奥

另请查看Itamar Turner-Trauring出色的Python Docker打包指南:pythonspeed.com/docker。按照他的建议,此答案可能应该更新为使用苗条的Debian映像而不是Alpine。
克劳迪奥

2
“请勿使用诗歌安装来安装您的代码,因为它将执行可编辑的安装。” 您可以使用--no-root标志禁用此行为。在此处查看已关闭的Github问题。
radzak

您可以使用poetry install --no-root而不是导出需求pip install。但这对可编辑的安装没有帮助。这个问题仍然悬而未决
克劳迪奥

11

这是对我有用的最小配置:

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的configuration安全。

作为一个琐事,我要补充一点,如果可以对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

2
如果案例中您的项目还包含mymodule您要安装的Python模块(如Poetry会在默认情况下找到一个模块),则需要在运行poetry install:之前创建一个虚拟版本,如下所示RUN mkdir /app/mymodule && touch /app/mymodule/__init__.py。之所以可行,是因为Poetry使用pip -e安装了这些类型的模块,而pip -e只会创建一个符号链接。这意味着在最后一步中将实际模块复制到其上时,事情将按预期进行。(根据mods的说法,这是一种评价而不是编辑-如果您不同意,请尝试将其合并到帖子中。)
Frankie Robertson

5

这是一个剥离的示例,其中首先将一个具有依赖项的层(仅在这些依赖项更改时才构建),然后将一个具有完整源代码的层添加到映像中。设置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 . ./

4

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最终可以得到更大的图像,并且要花一些时间才能完成。构建(有关更多信息,请阅读本文)。

  • 使用此配置生成容器的速度比使用高山映像更快,因为我不需要添加一些额外的软件包即可正确安装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才能正常工作。


4

这是@Claudio提供答案的次要修订,它使用了@sobolevn在其答案中poetry install --no-root描述的新功能。

为了强制诗歌将依赖项安装到特定的virtualenv中,需要首先启用它。

. /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作为基础,但是,使其适应于基于高山的图像应该是一件简单的任务。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.