【问题标题】:Integrating Python Poetry with Docker将 Python 诗歌与 Docker 集成
【发布时间】:2019-05-18 23:58:38
【问题描述】:

你能给我一个Dockerfile 的例子吗,我可以在其中将我需要的所有软件包从poetry.lock 和pyproject.toml 安装到我的Docker 镜像/容器中?

【问题讨论】:

    标签: python docker dockerfile python-poetry


    【解决方案1】:

    将poetry 与docker 一起使用时要记住几件事。

    安装

    安装poetry的官方方法是通过:

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

    这种方式允许poetry 及其依赖项与您的依赖项隔离。但是,在我看来,这不是一件好事,原因有两个:

    1. poetry 版本可能会得到更新,它会破坏你的构建。在这种情况下,您可以指定 POETRY_VERSION 环境变量。安装人员会尊重它
    2. 我不喜欢将来自 Internet 的内容通过管道传输到我的容器中而不受任何可能的文件修改保护的想法

    所以,我使用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 标志的生产。

    您可能还想添加更多选项以获得更好的体验:

    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

    【讨论】:

    • 这个答案的读者可以care to learn about Docker multi-stage builds。我知道在我的案例中,多阶段构建大大简化了基础、测试和应用 docker 镜像的过程。 See also this post 不是特定于诗歌的,但说明了在进行多阶段构建时可能考虑继续在 docker 中使用 virtualenv 的原因。 (自己还没测试,最近才采用poetry。)
    • @sobolevn pip install poetry 唯一担心的是 Poetry 的依赖可能与应用依赖冲突。
    • poetry config virtualenvs.create false 在 1.0.0 中不起作用。请改用RUN POETRY_VIRTUALENVS_CREATE=false poetry install。
    • 其实用pip installdo安装诗歌会和app依赖冲突,因为诗歌依赖也有自己的依赖。它完全在开发商的控制之下。使用此方法时,始终建议使用pip install --ignore-installed。我也不喜欢直接在 shell 中从 Internet 上传送一些东西。更不用说它需要 curl、wget 或其他任何东西。但是,如果你决定这样做,get-poetry.py 脚本有 --version 选项。
    • 这个方法对我来说很重要:在我的项目的pyproject.toml 中,我已经正常设置了所有内容。但是,pip install poetry(在 Python 3.7 上)按预期将appdirs 安装为poetry 的依赖项。但是当使用config virtualenvs.create false 运行时,poetry 运行“bare-metal”,并且再次删除 appdirs(Removing appdirs (1.4.4),同时安装正常的项目依赖项很好)。这是因为appdirs 没有在pyproject.toml 中列出(因为为什么会这样?)。我再次恢复使用虚拟环境,因此poetry 不会删除appdirs。
    【解决方案2】:

    使用 Poetry 和 venv 构建多阶段 Docker

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

    使用poetry export 并首先安装您的固定需求,然后再复制您的代码。这将允许您使用 Docker 构建缓存,并且永远不会仅仅因为您更改了代码中的一行而重新安装依赖项。

    不要使用poetry install 来安装您的代码,因为它会执行可编辑的安装。相反,使用poetry build 构建一个轮子,然后将其 pip-install 安装到您的 virtualenv 中。 (感谢PEP 517,整个过程也可以使用简单的pip install . 来执行,但由于build isolation,您最终会安装另一个Poetry 副本。)

    这是一个将 Flask 应用程序安装到 Alpine 映像中的示例 Dockerfile,它依赖于 Postgres。此示例使用入口点脚本来激活 virtualenv。但一般来说,没有入口点脚本应该没问题,因为您可以在 CMD 指令中简单地引用位于 /venv/bin/python 的 Python 二进制文件。

    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 发布。导出需求不再需要预发布。
    • 还可以查看 Itamar Turner-Trauring 为 Python 编写的优秀 Docker 打包指南:pythonspeed.com/docker。按照他的建议,这个答案可能应该更新为使用纤薄的 Debian 映像而不是 Alpine。
    • "不要使用诗歌安装来安装您的代码,因为它会执行可编辑的安装。"您可以使用 --no-root 标志禁用此行为。查看已关闭的 Github 问题 here。
    • 你不必使用. /venv/bin/activate,在Dockerfile中使用ENV PATH="/venv/bin:${PATH}"和ENV VIRTUAL_ENV="/venv"就足够了,这意味着你可以有一个内联入口点/cmd,它仍然会使用venv.
    【解决方案3】:

    TL;DR

    我已经能够使用postgres 为Django 项目设置poetry。经过一番研究,我最终得到了以下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,你实际上最终可以得到一个更大的图像,并且需要一段时间来构建(阅读this article了解更多信息)。

    • 使用此配置构建容器比使用 alpine 映像更快,因为我不需要添加一些额外的包来正确安装 Python 包。

    • 我直接从文档中提供的 URL 安装 poetry。我知道sobolevn 提供的警告。但是,我认为从长远来看,默认使用 poetry 的最新版本比依赖我应该定期更新的环境变量更好。

    • 更新环境变量PATH 至关重要。否则,你会得到一个错误提示 poetry was not found。

    • 依赖项直接安装在容器的python解释器中。它不会在安装依赖项之前创建poetry 来创建虚拟环境。

    如果您需要此Dockerfile 的alpine 版本:

    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 的某些新版本中的重大突破性更改可能会破坏您的整个构建,因此您必须对其进行修改以使用硬编码的发布版本
    【解决方案4】:

    这是适合我的最小配置:

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

    作为琐事,我将添加if editable installs will be possible for pyproject.toml projects,可以删除一两行:

    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 安装这些类型的模块,它只是创建一个符号链接。这意味着当在最后一步复制真实模块时,事情会按预期工作。 (根据模组,这是评论而非编辑 - 如果您不同意,请尝试将其合并到帖子中。)
    【解决方案5】:

    这是对answer provided by @Claudio 的次要修订,它使用@sobolevn in his answer 所述的新poetry install --no-root 功能。

    为了强制poetry 将依赖项安装到特定的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 作为基础,但是,将其调整为基于 alpine 的图像应该是一项微不足道的任务。

    【讨论】:

    • 所以我真的很喜欢这个答案,但是我将如何处理本地路径依赖关系?
    • 本地路径依赖是什么意思?
    • 路径依赖在 monorepo 设置中很有用,您在 repo 的其他地方共享库,请参阅the docs
    • 我想在RUN poetry install 或RUN poetry build 之前添加相应的COPY 命令?我的答案(以及引用的答案)实际上只是复制了容器中的设置,只是我们明确地将 venv 设置为/venv/,如果容器中的设置与您的工作设置相同,那么从技术上讲,一切都应该运行良好,想想你如何在没有 docker 的情况下在其他地方复制设置并相应地调整 Dockerfile?
    • @Jeffrey04 COPY 中的本地包对我不起作用。我在命令RUN . /venv/bin/activate && pip install *.whl 期间得到pip._vendor.pkg_resources.RequirementParseError: Invalid URL: my-package
    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

      我创建了一个使用锁包(取决于锁文件中所有版本的包)的解决方案。这会导致没有要求文件的纯 pip 安装。

      步骤是:构建包,构建锁包,将两个轮子复制到容器中,用 pip 安装两个轮子。

      安装为:poetry add --dev poetry-lock-package

      docker build 之外的步骤是:

      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 会将所有内容安装到站点包中。
      【解决方案8】:

      我看到这里所有的答案都是使用 pip 方式安装 Poetry 以避免版本问题。 安装诗歌的官方方式读取 POETRY_VERSION 环境变量,如果定义为安装最合适的版本。

      github here 有一个问题,我认为这张票的解决方案很有趣:

      # `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 的情况下工作。它实际上使用 venvs 来进行依赖管理。也就是说,人们可能想要 venvs 的另一个原因是他们是否使用了无发行容器。它的完成方式是通过多阶段构建并将 venv(它仅具有给定应用程序所需的 python 依赖项)移动到一个专用容器,而不需要整个操作系统的混乱。许多 Flask 应用程序都是这样完成的。当然,除非您喜欢演出大小的容器 - 使它们不太便携。容器大小不仅仅关乎安全性和攻击面。
      • @BrandonStivers 如果你想写一篇文章,请在这里 - stackoverflow.com/questions/68936213/…
      【解决方案9】:

      您可以在两个项目中了解如何正确执行此操作,或者您可以使用这些项目来构建您自己的图像,因为它们只是基础图像:

      基础镜像的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/
      

      【讨论】:

        【解决方案10】:

        这是一种使 Poetry 保持完整的不同方法,因此您仍然可以使用 poetry add 等。如果您使用的是 VS Code 开发容器,这很好。

        简单来说就是安装Poetry,让Poetry创建虚拟环境,然后每次启动新shell通过修改.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。 doesn't affect performance 和 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 和 lock 文件,您是手动创建的还是先在主机上使用诗歌来创建项目?如果是这样,为什么要使用带有 vscode 的远程容器?
        • 好点 - 这在新的回购中不起作用。它假定您已经手动设置了 Poetry。如果文件可用,您可以修改该部分以复制文件。我在上面的答案中添加了一个建议。
        【解决方案11】:

        使用docker多阶段构建和python slim镜像,将诗歌锁导出到requirements.txt,然后在virtualenv中通过pip安装。

        它具有最小尺寸,不需要诗歌在运行时映像中,固定所有版本。

        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
        

        【讨论】:

          猜你喜欢
          • 2022-01-11
          • 2021-04-22
          • 2022-06-15
          • 2022-07-22
          • 1970-01-01
          • 2022-08-12
          • 1970-01-01
          • 2020-12-07
          • 2022-01-26
          相关资源
          最近更新 更多