[英]Docker can't find Python venv executable
我正在尝试为我的烧瓶应用程序创建一个 Docker 映像,如下所示:
# syntax=docker/dockerfile:1
FROM python:3.9.5-slim-buster as build
RUN python3 -m venv /app/venv
COPY . /app
RUN /app/venv/bin/pip install -r /app/requirements.txt
FROM gcr.io/distroless/python3
COPY --from=build /app /app
# ENV PATH = "/app/venv/bin:${PATH}"
EXPOSE 5000
ENTRYPOINT [ "/app/venv/bin/python3" , "main.py"]
基本上,我有两个构建阶段:第一个使用venv
创建虚拟环境,第二个使用 distroless 映像并将虚拟环境(连同我的其余文件)从前一个构建阶段复制到新的。
Docker 映像构建没有问题,但是一旦我尝试使用docker run
运行映像,我会收到以下错误:
docker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "/app/venv/bin/python3": stat /app/venv/bin/python3: no such file or directory: unknown.
这个错误让我很困惑,因为我知道 python 可执行文件位于/app/venv/bin
,我通过使用docker export <container name> > container.tar
并探索 tar 文件的内容来仔细检查这一点。 据我所知,我不应该收到这个错误。
我究竟做错了什么?
编辑:根据@RQDQ 的要求,以下是我的requirements.txt
和main.py
的最低版本:
requirements.txt
:
click==8.1.3
Flask==2.1.2
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.0.1
Werkzeug==2.1.2
main.py
:
from flask import Flask
app = Flask(__name__, static_folder='build')
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
if (__name__ == "__main__"):
app.run(use_reloader=False, host='0.0.0.0', port=5000, threaded=True)
virtualenv
不是可以在操作系统(或容器)之间复制的独立环境:
$ python -m venv venv
$ ls -l venv/bin/
total 36
-rw-r--r-- 1 user user 1990 Jun 2 08:35 activate
-rw-r--r-- 1 user user 916 Jun 2 08:35 activate.csh
-rw-r--r-- 1 user user 2058 Jun 2 08:35 activate.fish
-rw-r--r-- 1 user user 9033 Jun 2 08:35 Activate.ps1
-rwxr-xr-x 1 user user 239 Jun 2 08:35 pip
-rwxr-xr-x 1 user user 239 Jun 2 08:35 pip3
-rwxr-xr-x 1 user user 239 Jun 2 08:35 pip3.10
lrwxrwxrwx 1 user user 46 Jun 2 08:35 python -> /home/user/.pyenv/versions/3.10.2/bin/python
lrwxrwxrwx 1 user user 6 Jun 2 08:35 python3 -> python
lrwxrwxrwx 1 user user 6 Jun 2 08:35 python3.10 -> python
如您所见, python
可执行文件只是指向原始 python 可执行文件的链接。 它类似于原始 python 的快照,可以恢复或应用。 但是如果你没有原始基础,快照是没有用的。 因此,您必须在将要使用的相同环境中创建venv
。
但是,对于容器,您根本不需要venv
。 容器已经是一个隔离的环境,您不需要使用 venv 再增加一个隔离级别。 (至少我关于为什么我们需要在容器内使用venv
的问题仍然没有答案)
简而言之:删除所有与venv
相关的行:
# syntax=docker/dockerfile:1
FROM gcr.io/distroless/python3
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT [ "python" , "main.py"]
但是,如果您在通过pip
安装 Python 库时需要一些额外的库/编译工具(如gcc
)来构建 Python 库,那么venv
可以用于仅移动生成的库二进制文件,而无需在容器内存储编译工具。
在这种情况下,您必须在build
映像和生成的映像中使用相同(或兼容的)python 库( venv
“快照”应该应用于兼容的库)。
让我们看看这个例子:
FROM debian:11-slim AS build
...
FROM gcr.io/distroless/python3-debian11
...
这两个图像至少基于Debian
。
或另一个例子:
FROM python:3.9-slim as compiler
...
FROM python:3.9-slim as runner
...
builder
和runner
的基础也是一样的
看起来python:3.9.5-slim-buster
和gcr.io/distroless/python3
都是基于 Debian 的,应该兼容,但可能不完全兼容。
您将端点更改为ENTRYPOINT [ "sleep" , "600"]
。 这将允许容器运行 10 分钟。 之后附加到正在运行的容器: docker exec -it container_name bash
并检查python
可执行文件是否存在: ls -l /app/venv/bin/
或者只是像我之前所说的那样在没有venv
的情况下使用它
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.