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



假设我用Docker写了一个docker-compose.dev.yml文件来设置一个Flask项目(web应用)的开发环境。在docker-compose.dev.yml中,我设置了两个服务,一个用于数据库,一个用于在调试模式下运行Flask应用程序(这允许我在不重新创建/重新启动容器的情况下进行热更改)。这使得开发团队中的每个人都可以很容易地使用相同的开发环境。然而,有一个问题:很明显,在开发应用程序时,有必要安装库,并在requirements.txt文件中列出它们(在Python的情况下)。对于这一点,我只看到了使用Docker开发环境的两种替代方案:

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

第一个选项有点费力,而第二个选项有点"肮脏"。有没有比上述两种选择更合适的选择?

编辑:我不知道我问的问题是否没有意义,但如果有人能给我一些指导,我将不胜感激。

对于这样的东西,我使用多层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(多层Dockerfile,在这个例子中:testruntime),像这样(不完整):

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

最后的想法:正如我在评论中提到的,处理这种依赖需求的更好方法可能是使用poetrypip-tools之类的工具,或者其他任何工具。


更新2022-05-23:

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

假设容器有一个特定的名称(<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

这个命令只是将新的依赖项安装到正在运行的容器中。

如果目标是有一个一致的开发环境,我能想到的最安全的方法是用更新的依赖关系构建一个基本映像,并发布到私有注册表,以便您可以引用特定的标记,如app:v1.2。所以Dockerfile可以像这样:

FROM AppBase:v1.2
...

这意味着不需要安装依赖项,并导致更快和一致的开发环境设置。

在外部挂载卷的容器内virtualenv中安装需求. 注意,虚拟环境的创建和安装应该在容器运行时进行,而不是在映像构建时进行(因为没有挂载卷)。

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

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

只是不要期望virtualenv可以在容器之外使用,例如通过您的IDE(但是使用site模块的一点黑客行为将让您与您的机器的virtualenv共享站点包)


这与通常在生产docker映像中管理需求的方式非常不同,在生产docker映像中,源和需求在映像构建时被复制和安装。因此,您可能需要两个非常不同的dockerfile用于生产部署和本地开发,就像您已经有了不同的docker-compose一样。yml文件。

但是,如果您希望两者更加相似,请记住,在生产docker映像中也使用虚拟环境并没有什么害处,尽管不这样做的趋势。

第二个选项通常用于python环境。你只需要将新包添加到requirements.txt中,然后重新启动容器,它的dockerfile中有一行pip install -r requirements.txt用于安装。