Home > Mobile >  Docker can't find Python venv executable
Docker can't find Python venv executable

Time:06-03

I am trying to create a Docker image for my flask application, shown below:

# 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"]

Basically, I have two build stages: the first one creates a virtual environment with venv, and the second uses a distroless image and copies the virtual environment (along with the rest of my files) from the previous build stage to the new one.

The Docker images builds without issue, but once I try to run the image with docker run, I get the following error:

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.

This error confuses me, since I know the python executable is located at /app/venv/bin, and I double checked this by exporting the container using docker export <container name> > container.tar and exploring the tar file's contents. From what I can tell, I should not be receiving this error.

What am I doing wrong?

Edit: As requested by @RQDQ, below are bare minimum versions of my requirements.txt and 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)

CodePudding user response:

virtualenv is not standalone environment that can be copied between OSes (or containers):

$ 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

As you can see python executables are just links to original python executable. It is something like snapshot for your original python that may be reverted or applied. But snapshot is useless if you don't have original base. So you have to create venv at same environment that will be used on.

However in case of containers you don't need venv at all. Container is already an isolated environment and you don't need one more isolation level with venv. (At least my question about why we need to use venv inside container is still don't have an answer)

In short: remove all venv related lines:

# 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"]

However if you need to some extra libraries/compile tools (like gcc) to build python libraries when installing it by pip then venv may be used to be able move only resulted library binaries without store compile tools inside container.

In this case you have to use same (or compatible) python base at build image and resulted image (venv "snapshot" should be applied to compatible base).

Let's see this example:

FROM debian:11-slim AS build
...

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

Both images at least Debian based.

Or another example:

FROM python:3.9-slim as compiler
...

FROM python:3.9-slim as runner
...

And again base of builder and runner is the same


Looks like python:3.9.5-slim-buster and gcr.io/distroless/python3 are both Debian based and should be compatible, but probably it is not fully compatible.

You change endpoint to ENTRYPOINT [ "sleep" , "600"]. That will allow to keep container running for 10 minutes. After that attach to running container: docker exec -it container_name bash and check is python executable exists: ls -l /app/venv/bin/

or just simply use it without venv as I said before

  • Related