Docker 找不到 Python venv 可执行文件

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.txtmain.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 的隔离级别。 (至少我的 question 为什么我们需要在容器内使用 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"]

然而,如果您需要一些额外的 libraries/compile 工具(如 gcc)来构建 python 库,那么 pip 安装它时 venv 可能用于仅移动生成的库二进制文件,而无需在容器内存储编译工具。

在这种情况下,您必须使用 相同(或兼容)python base at build image 和结果图像(venv " snapshot”应该应用于兼容的基础。

让我们看看this example:

FROM debian:11-slim AS build
...

FROM gcr.io/distroless/python3-debian11
...

两张图片至少 Debian 基于。

another example:

FROM python:3.9-slim as compiler
...

FROM python:3.9-slim as runner
...

builderrunner 的基数相同


看起来 python:3.9.5-slim-bustergcr.io/distroless/python3 都是 Debian based 并且应该兼容,但可能不完全兼容。

您将端点更改为 ENTRYPOINT [ "sleep" , "600"]。这将允许容器 运行 保持 10 分钟。之后附加到 运行 容器:docker exec -it container_name bash 并检查是否存在 python 可执行文件:ls -l /app/venv/bin/

或者就像我之前说的那样,不用 venv 就直接使用它