Search code examples
pythondockerfastapipython-poetrybuilder-pattern

starting container process caused: exec: "fastapi": executable file not found in $PATH: unknown


I am trying to Dockerize my fastapi application, but it fails with the following error

Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "fastapi": executable file not found in $PATH: unknown

Can someone help me out?

Dockerfile

FROM python:3.12 as builder

# install and setup poetry config
RUN pip install poetry==1.8.2

ENV POETRY_NO_INTERACTION=1 \
    POETRY_VIRTUALENVS_IN_PROJECT=1 \
    POETRY_VIRTUALENVS_CREATE=1 \
    POETRY_CACHE_DIR=/tmp/poetry_cache

WORKDIR /navigation

COPY pyproject.toml poetry.lock ./
# poetry complains if there is no README file
RUN touch README.md

# install without dev dependencies + remove poetry cache
RUN poetry install --without dev && rm -rf $POETRY_CACHE_DIR

FROM python:3.12-alpine as runtime

ENV VIRTUAL_ENV=/navigation/.venv \
    PATH="/navigation/.venv/bin:$PATH"

COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}

COPY navigation ./navigation

CMD ["fastapi", "run", "main.py", "--proxy-headers", "--port", "80"]

docker-compose.yml

services:
  navigation-api:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./navigation:/navigation

I'm using poetry (as can be seen in the Dockerfile) to install my dependencies. Here are my dependencies in my pyproject.toml file.

pyproject.toml

[tool.poetry.dependencies]
python = ">=3.12,<3.13"
fastapi = "^0.111.0"
prisma = "^0.13.1"

I also tried to use uvicorn instead of using the fastapi-cli, but the same error occurs.

I tried to not use the builder pattern to see if it was an issue there. But the same error.

I checked this ticket out, but no solutions offered worked: starting container process caused: exec: "uvicorn": executable file not found in $PATH: unknown


Solution

  • There's two things that are obvious problems in the setup you show.

    In the Compose file, you should delete:

        volumes:
          - ./navigation:/navigation
    

    This overwrites the /navigation directory in the image – everything the Dockerfile sets up other than the base image – with content from the host. That includes your virtual environment, which is in /navigation/.env. This is probably directly causing the error you see.

    (If it's important to you that the running program sees the code on your local system without rebuilding the image, this setup is almost like an ordinary Python virtual environment, except you've placed the Python interpreter in a container where it's hard to run and hard for an IDE to see it. Using a plain virtual environment without Docker will be better.)

    In the Dockerfile, the base images of the two build stages need to match. Your current setup looks like this:

    FROM python:3.12 as builder
    ...
    FROM python:3.12-alpine as runtime  # <-- doesn't match first stage
    COPY --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV}
    

    Virtual environments can be extremely specific to the Python they're built against. You can hit some obscure hard-to-debug errors if the two Pythons don't match exactly. For Python in particular, I'd recommend generally using the Debian-based images (with no suffix or with a "-slim" suffix) and not Alpine, since the Debian-based images can install precompiled "wheel" format images often without requiring a C toolchain.