使用Docker开发环境时如何处理Python的requirements.txt?

How to deal with Python's requirements.txt while using a Docker development environment?

假设我使用Docker编写了一个docker-compose.dev.yml文件来设置Flask项目(web应用程序)的开发环境。在 docker-compose.dev.yml 中,我设置了两项服务,一项用于数据库,一项用于 运行 处于调试模式的 Flask 应用程序(这使我无需 recreate/restart 容器即可进行热更改) .这使得开发团队中的每个人都可以非常轻松地使用相同的开发环境。但是,有一个问题:很明显,在开发应用程序时,必须安装库,并将它们列在 requirements.txt 文件中(在 Python 的情况下)。为此,我只看到两个使用 Docker 开发环境的替代方案:

  1. 进入Flask应用运行ning所在容器的控制台,使用pip install ...pip freeze > requirements.txt命令
  2. 手动将依赖项写入 requirements.txt 文件并重建容器。

第一个有点费力,第二个有点“脏”。还有比这两个更合适的选择吗?

编辑:我不知道我是否在问一些没有意义的问题,但如果有人能给我一些关于我正在努力完成的事情的指导,我将不胜感激。

第二个选项一般用于python环境。您只需将新软件包添加到 requirements.txt 并重新启动容器,该容器在其 dockerfile 中有一行 pip install -r requirements.txt 来执行安装。

如果目标是拥有一致的开发环境,我能想到的最安全的方法是使用更新的依赖项构建基础映像并发布到私有注册表,这样您就可以引用特定的标签,例如app:v1.2。所以 Dockerfile 看起来像:

FROM AppBase:v1.2
...

这意味着无需安装依赖项,从而实现更快、更一致的开发环境设置。

在外部安装卷 的容器内的virtualenv 中安装要求。请注意,virtualenv 的创建和安装应该发生在容器 运行 时间,而不是图像构建时间(因为没有安装卷)。

假设您已经安装(不是复制!)您的项目源,您可以将它保存在 ./.venv 文件夹中,这是一个相当标准的过程。

然后你就像在本地工作一样:第一次设置项目时发出安装一次,除非需求发生变化,否则不需要重新安装需求,即使重建容器也可以保留venv,重新启动该应用程序不会每次都重新安装要求等等

只是不要期望 virtualenv 在容器外可用,例如通过你的 IDE(但是对 site 模块进行一些黑客攻击可以让你与你机器的 virtualenv 共享 site-packages)


这是一种与通常在生产 docker 映像中管理需求的方式截然不同的方法,其中源和需求在映像构建时被复制和安装。因此,您可能需要两个非常不同的 Dockerfile 来进行生产部署和本地开发,就像您已经有不同的 docker-compose.yml 文件一样。

但是,如果您希望它们更相似,请记住在生产 docker 映像中也使用 virtualenv 没有坏处,尽管不这样做的趋势。

对于这样的事情,我使用 multi-layer docker 图片。

免责声明:以下示例未经测试。请将其视为用伪代码编写的纯粹描述;)

作为一个非常简单的示例,此方法可能如下所示:

# Make sure all layers are based on the same python version.
FROM python:3.10-slim-buster as base

# The actual dev/test image.
# This is where you can install additional dev/test requirements.
FROM base as test
COPY ./requirements_test.txt /code/requirements_test.txt
RUN python -m pip install --no-cache-dir --upgrade -r /code/requirements_test.txt

ENTRYPOINT ["python"]
# Assuming you run tests using pytest.
CMD ["-m", "pytest", "..."]

# The actual production image.
FROM base as runtime
COPY ./requirements.txt /code/requirements.txt
RUN python -m pip install --no-cache-dir --upgrade -r /code/requirements.txt

ENTRYPOINT ["python"]
# Assuming you wantto run main.py as a script.
CMD ["/path/to/main.py"]

requirements.txt 像这样(只是一个例子):

requests

requirements_test.txt 像这样(只是一个例子):

-r requirements.txt

pytest

在您的 docker-compose.yml 文件中,您只需要传递 --target(属于 multi-layered Dockerfile,在本例中:testruntime),例如这个(不完整):

services:
  service:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: runtime  # or test for running tests

最后一个想法: 正如我在评论中提到的,处理此类依赖性要求的更好方法可能是使用 poetrypip-tools - 或者其他任何东西。


更新 2022-05-23:

如评论中所述,为了完整起见,并且因为这种方法可能接近可能的解决方案(如问题中所要求的):

fire-and-forget 方法的示例如下所示 - 假设容器具有特定名称 (<containe_name>):

# This requires to mount the file 'requirements_dev.txt' into the container - as a volume.
docker exec -it <container_name> python -m pip install --upgrade -r requirements_dev.txt

此命令只是将新的依赖项安装到 运行 容器中。