Search code examples
pythondocker-composedockerfilefastapipython-poetry

Can not launch Python FastAPI project with Docker


I am quite new to programming and have an error trying to lauch fastapi project with Docker and Poetry.

Here is my project structure:

.
├── backend
│   ├── Dockerfile
│   ├── poetry.lock
│   ├── pyproject.toml
│   ├── src
│   │   ├── domain
│   │   │   └── __init__.py
│   │   ├── infrastructure
│   │   │   └── __init__.py
│   │   ├── __init__.py
│   │   └── presentation
│   │       ├── __init__.py
│   │       └── main.py
│   └── tests
│       └── __init__.py
├── docker-compose.yaml
└── README.md

Here is Docker file:

FROM python:3.11-slim

WORKDIR /backend

COPY . /backend

RUN pip install --upgrade pip && pip install poetry
RUN poetry install

EXPOSE 8000

and docker-compose.yaml:

services:

  # PostgreSQL
  db:
    image: postgres
    restart: always
    env_file:
      - backend/.env
    ports:
      - '5432:5432'
    healthcheck:
      test: [ "CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}'" ]
      interval: 10s
      timeout: 3s
      retries: 3

  # BackEnd
  backend:
    build:
      context: backend
    command: bash -c 'uvicorn src.presentation.main:app --host 0.0.0.0 --port 8000 --reload'
    ports:
      - '8000:8000'
    volumes:
      - .:/backend
    restart: always
    depends_on:
      db:
        condition: service_healthy

My pyproject.toml:

[tool.poetry]
name = "startup"
version = "0.1.0"
description = ""
authors = ["RRoxxxsii <mishabur38@gmail.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
fastapi = {extras = ["all"], version = "^0.109.0"}
pytest="^7.4.4"
pytest-asyncio = "^0.23.3"
pre-commit = "^3.6.0"
sqlalchemy = "^2.0.25"
alembic = "^1.13.1"
uvicorn = "^0.25.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

When I start the project with docker compose up I get the error:

bash: line 1: uvicorn: command not found

And I do not understand why, as I have uvicorn inside poetry.lock and pyproject.toml


Solution

  • ok so I tried to reproduce the above,

    I think there are a few things here to point out,

    1. Poetry related

      • 1a. poetry will look for a directory with the same name as the project name in the pyproject.toml file in this case it should be startup/ under your backend/ directory
      • 1b. poetry will also complain and fail to install the current project if it doesn't find a README.md under the backend/ directory, in this case the root dir of the project "startup"
    2. Docker related

      • In your compose file you have the host volume . mapped to container dir /backend, and on top of that you have COPY . /backend, I suspect this does a funny overwrite operation, although, I'm not 100% sure what happens there but someone more familiar with the docker mounting system would clarify it better than me.

    However, I got around it by changing the workdir name to something other than /backend like /service in the below reproducible example

    docker-compose.yml

    services:
    
      # BackEnd
      backend:
        build:
          context: backend
        command: bash -c 'poetry run uvicorn startup.main:app --host 0.0.0.0 --port 8000 --reload'
        ports:
          - '8000:8000'
        volumes:
          - .:/backend
    
    

    Dockerfile

    FROM python:3.11-slim
    
    WORKDIR /service
    
    COPY . /service
    
    RUN pip install --upgrade pip && pip install poetry
    RUN poetry install
    
    EXPOSE 8000
    
    

    directory structure

    .
    ├── backend
    │   ├── Dockerfile
    │   ├── pyproject.toml
    │   ├── README.md
    │   └── startup
    │       ├── __init__.py
    │       └── main.py
    └── docker-compose.yaml