I got this up and running locally, and was able to get it working with Docker when I put command: uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000
in docker-compose.yaml
; and I didn't have the uvicorn
call in main.py
.
Of course when I made further changes, particularly placing the uvicorn
call in main.py
, things went down hill. Now I get the following Docker error:
/.venv/bin/python: can't find '__main__' module in '/home'
Please note the backend/main.py
file below does work successfully when I run it locally; but of course I have an issue with Docker.
Here's what I have thus far:
Folder Structure
├── backend
│ ├── .docker
│ │ ├── Dockerfile
│ ├── __init__.py
│ ├── .env
│ ├── main.py
├──docker-compose.yaml
docker-compose.yaml
version: "3.9"
services:
backend:
build:
context: ./backend
dockerfile: .docker/Dockerfile
env_file:
- ./backend/.env
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- 8000:8000
volumes:
- .:/home
backend/.docker/Dockerfile
FROM python:3.11.3-slim-buster as base
# Setup env
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
# Prevent Python from writing .pyc files to disk
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONFAULTHANDLER 1
# Ensure Python output is sent straight to terminal
ENV PYTHONUNBUFFERED 1
FROM base AS python-deps
# Update container essentials
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
gcc postgresql-client \
&& apt-get clean
# Install pipenv
RUN pip install --upgrade pip
RUN pip install pipenv
# Install python dependencies in /.venv
COPY Pipfile .
COPY Pipfile.lock .
RUN PIPENV_VENV_IN_PROJECT=1 pipenv install --deploy
FROM base AS runtime
# Copy virtual env from python-deps stage
COPY --from=python-deps /.venv /.venv
ENV PATH="/.venv/bin:$PATH"
WORKDIR /home
# Install application into container
COPY . .
CMD python . main.py
backend/.env
COMPOSE_PROJECT_NAME=i_need_help
ENV=dev
APP_MODULE=app
HOST=0.0.0.0
PORT=8000
backend/main.py
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI(
title="I Need Help",
version="0",
)
@app.get("/health")
async def health() -> JSONResponse:
return { "message": "OK" }
if __name__ == "__main__":
import os
import uvicorn
uvicorn.run(
os.getenv("APP_MODULE"),
host=os.getenv("HOST"),
port=int(os.getenv("PORT")),
reload=True
)
All help is appreciated - thanks in advance.
CMD python . main.py
This looks incorrect. When you provide a directory (.
is /home
in this case) as the first argument to python
it will look for a __main__.py
file in that directory and attempt to execute it within the namespace of the provided directory. You have no __main__.py
file anywhere -- this is the source of the error message you are receiving.
The string main.py
is simply being provided as an argument in this case.
You probably wanted to do something like this:
CMD ["python", "backend/main.py"]
Alternatively, create the file backend/__main__.py
something like this:
# backend/__main__.py
import uvicorn, os
uvicorn.run(
'backend.main:app',
host=os.getenv("HOST"),
port=int(os.getenv("PORT")),
reload=True
)
Then you can run your project as a package by doing this in your dockerfile:
CMD ["python", "-m", "backend"]