由Itamar Turner-Trauring 最后更新2020年6月25日,最初创建于2019年3月20日
在Docker映像中打包Python应用程序时,通常会使用virtualenv
。例如,您可能正在执行多阶段构建以获取较小的镜像。
由于您正在使用virtualenv
,因此需要激活它-但是,如果您只是开始使用 Dockerfile,那么幼稚的方法将不起作用。即使您确实知道该怎么做,通常的方法也是重复性的,因此容易出错。
有一种激活virtualenv的简单方法,我将在本文中进行演示。 但是首先,我们将介绍其他一些不太优雅(或损坏!)的方法。
注意:在所讨论的主题之外,本文中的Dockerfile并不是最佳实践的示例,因为增加的复杂性将使本文的重点难以理解。因此,如果要使用Docker在生产环境中运行Python应用程序,可以采用以下两种方法来应用最佳实践:
- 如果您想自己动手做:详细的清单,包括示例和参考
- 如果您希望尽快进行有效的设置:一个模板,其中已为您实施了最佳实践
如果您只是将shell脚本盲目地转换为Dockerfile,则会得到看起来正确但实际上已损坏的内容:
FROM python:3.8-slim-buster RUN python3 -m venv /opt/venv # This is wrong! RUN . /opt/venv/bin/activate # Install dependencies: COPY requirements.txt . RUN pip install -r requirements.txt # Run the application: COPY myapp.py . CMD ["python", "myapp.py"]
它的中断有两个不同的原因:
RUN
Dockerfile中的每一行都是一个不同的过程。activate
单独运行RUN
不会影响以后的RUN
通话。出于所有实际目的,这是无人操作的。CMD
-也将不会在virtualenv内部运行,因为它也不受RUN
进程的影响。一种解决方案是显式使用virtualenv中二进制文件的路径。在这种情况下,我们只有两次重复,但是在更复杂的情况下,您需要一遍又一遍。
除了缺乏可读性之外,重复也是错误的根源。当您向Python程序添加更多调用时,很容易忘记添加魔术/opt/venv/bin/
前缀。
它将(大部分)工作:
FROM python:3.8-slim-buster RUN python3 -m venv /opt/venv # Install dependencies: COPY requirements.txt . RUN /opt/venv/bin/pip install -r requirements.txt # Run the application: COPY myapp.py . CMD ["/opt/venv/bin/python", "myapp.py"]
唯一需要注意的是,如果任何Python进程启动了子进程,则该子进程将_不会_在virtualenv中运行。
您可以通过分别分别单独激活virtualenv RUN
和:来解决此问题CMD
:
FROM python:3.8-slim-buster RUN python3 -m venv /opt/venv # Install dependencies: COPY requirements.txt . RUN . /opt/venv/bin/activate && pip install -r requirements.txt # Run the application: COPY myapp.py . CMD . /opt/venv/bin/activate && exec python myapp.py
(在exec
那里可以得到正确的信号处理。)
人们很容易将其想象activate
为某种神秘的魔术,一种被鲜血吸引住的五芒星,以使Python安全地被困住。但这只是软件,而且是相当简单的软件。 virtualenv文档甚至会告诉您activate
“绝对方便”。
如果您去阅读的代码activate
,它将执行许多操作:
deactivate
功能添加到您的shell中,并与混淆pydoc
。PYTHONHOME
如果有人碰巧设置了环境变量,它将取消设置环境变量。VIRTUAL_ENV
和PATH
。前四个基本上与Docker的使用无关,因此只剩下最后一个。大多数时候VIRTUAL_ENV
没有作用,但是某些工具(例如poetry
打包工具)使用它来检测您是否在virtualenv中运行。
最重要的部分是设置PATH
:PATH
是要搜索要运行的命令的目录列表。 activate
只需将virtualenv的bin/
目录添加到列表的开头。
我们可以activate
通过设置适当的环境变量来代替:Docker的ENV
命令将后续RUN
以及都应用于CMD
。
结果是以下Dockerfile:
FROM python:3.8-slim-buster ENV VIRTUAL_ENV=/opt/venv RUN python3 -m venv $VIRTUAL_ENV ENV PATH="$VIRTUAL_ENV/bin:$PATH" # Install dependencies: COPY requirements.txt . RUN pip install -r requirements.txt # Run the application: COPY myapp.py . CMD ["python", "myapp.py"]
现在,virtualenv可以自动为RUN
和两者使用CMD
,而无需重复或无需记住任何内容。
事情就在这里:一个与原始的原始版本一样简单的版本,但实际上做对了。无重复,错误范围更小。
当某些东西看起来不必要地复杂时,请深入研究并弄清楚它是如何工作的。您使用的软件可能比您想象的更简单(或更简单),并且只需花费少量工作便可以提供更优雅的解决方案。
____________________________________ / You may be gone tomorrow, but that \ | doesn't mean that you weren't here | \ today. edited by Yujiaao / ------------------------------------ \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
© 2020 Hyphenated Enterprises LLC. All rights reserved.