如何使带有诗歌和 pyproject.toml 的 python 包的开发环境和生产环境之间的依赖关系保持一致

How to keep dependencies consistent between dev and production env for a python package with poetry and pyproject.toml

我有一个 python 包,其中的依赖项在 poetry.lock 文件中指定用于开发和测试。然后我构建并发布了安装在生产 docker 图像上的包。但问题是:已发布的包在 pyproject.toml 的 tool.poetry.dependencies 部分中指定了其依赖项,这可能与 poetry.lock 不同。因此,生产环境最终可能与测试环境具有不同的依赖关系。

我可以想出几种方法来实现一致性,但是 none 对我来说似乎很好:

  1. 在 pyproject.toml 中使用与 poetry.lock 中相同的版本集。这将保证发布的包具有与 dev/test 相同的依赖关系。但是此时保留 poetry.lock 文件有什么意义,因为如果没有 poetry.lock 文件,pyproject.toml 也可以用于 poetry install。我认为这行得通,但我不明白为什么一开始还要 poetry.lock。

  2. 在生产 docker 映像中,在安装软件包本身之前从软件包 repo 和 运行 poetry install 中检出 poetry.lock 文件。但这会增加 docker 图像大小,如果 repo 是私有的,则会引入不必要的配置,并且总体上看起来不自然。

我对 Python 的这一部分还很陌生,所以也许其中之一就是“标准”工作流程。或者也许我只是完全错过了一些东西。感谢您的回答!

选项 1:不建议按照选项 1 中的描述确定依赖版本,因为它会导致不必要的严格包。这通常会导致本可避免的冲突,尤其是当您编写的包也是对其他项目的内部依赖时。

选项2:像这样处理依赖项肯定比选项1好,但比我想提出的选项更难维护。作为旁注,它还需要在您的 docker 图像上安装诗歌 - 如果您只想安装软件包,您只需要 pip

选项 3:在构建管道的开头创建一个 wheelhouse,并在后续步骤中使用它来安装运行时依赖项。这确保了测试代码和部署代码之间不可能存在差异,而且速度非常快,因为无需从 Internet 下载或构建纯源代码分发版。我将使用一个示例 .gitlab-ci.yml 来说明我的意思,但是这个概念应该可以毫无问题地转化为其他所有内容 CI/CD:

.gitlab-ci.yml

image: acaratti/pypoet
# a simple python:slim image that comes with poetry preinstalled

stages:
  - build
  - test
  - release

variables:
  WHEELHOUSE: wheelhouse 
  POETRY_VIRTUALENVS_PATH: venv  # speeds up jobs
  IMAGE_NAME: my-app

wheels:
  stage: build
  script:
    - poetry install
    - poetry build -f wheel
    - poetry export -f requirements.txt -o requirements.txt
    - poetry run pip wheel -w ${WHEELHOUSE} -r requirements.txt
    - mv dist/* ${WHEELHOUSE}
  artifacts:
    expire_in: 1 week
    paths:
      - ${WHEELHOUSE}
      - ${POETRY_VIRTUALENVS_PATH}

pytest:
  stage: test
  script:
    # no need to run `poetry install` because 
    # the venv from the build-job gets re-used
    - poetry run pytest

dockerize:
  stage: release
  image: docker:git
  script:
    - docker build . -t ${IMAGE_NAME}
    - docker push ${IMAGE_NAME}

如果您在 docker化过程中有这样的操作室可用,Dockerfile 本身通常就足够简单了:

Dockerfile

FROM python:3.9-slim

COPY wheelhouse/* wheelhouse/

RUN pip install wheelhouse/*

ENTRYPOINT ["run", "my", "app"]

注意事项

您用于 wheel 作业的图像需要与 docker 文件中的基本图像相同的拱门(或任何试图安装驾驶室或重新使用的作业)虚拟环境)——如果你在你的 gitlab 工作中使用 debian,但在 prod-image 中使用 alpine,事情会很快崩溃。

这也扩展到在本地构建图像,如果这是您在开发过程中想要做的事情。如果您的工作站有不同的拱门,例如ubuntu,您可能无法再这样做了。 Here 是一个在您的工作站上创建基于 debian 的工作驾驶室的秘诀。