pythondockerfastapiuv

Is there an issue with starting a FastAPI backend within Docker using uv run main.py?


I'm setting up a FastAPI backend with Docker on my machine (will be deployed to Azure later as well) right now. All examples I have seen including the official uv docker example start the backend like this in Docker:

FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
# ... 
CMD ["fastapi", "dev", "--host", "0.0.0.0", "src/uv_docker_example"]

They use the fastapi cli to start the backend with the starting configuration being specified within Docker.

However I use variables for my starting configuration that I effectively get from a .env file (which gets validated using pydantic-settings first)

# ./main.py
import uvicorn
from fastapi import FastAPI
# ...
if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=config.fastapi_port, workers=config.workers,
                log_level="info", reload=True)

I therefore tried to start the backend in docker the same way by invoking the main.py file itself. This way all .env variables get read and validated first and then the startup config gets filled dynamically.

FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
# ... 
CMD ["uv", "run", "main.py"]

This seems to work fine at first glance. At least I could not find anything wrong with it. However since I did not see anyone else doing it like this I'd like to know if there is any major downside of doing it this way that I'm missing right now? In theory this should also work on properly on Azure since I pass the env variables using the Azure Environment Variables page in the web app configuration but I'm not entirely sure. Can someone please clarify this?


Solution

  • In a comment you clarify:

    I'm probably looking for a way to dynamically set the nr of workers somewhere without needing to specify this twice

    In the Uvicorn Settings documentation, it notes that environment variables with names beginning with UVICORN_ directly translate to Uvicorn settings, and also that these must be proper environment variables and not from a --env-file. That means, without changing anything at all in your code or your image build, you can set the worker count when you run the container.

    docker run -d -p 8080:8080 \
      -e UVICORN_WORKERS=8 \
      my-image
    

    If the variable is already set in the host environment, you can use the -e option without a value.

    $ cat .envrc
    export UVICORN_WORKERS=8
    $ uv run fastapi dev
    ...
    $ docker run -d -p 8080:8080 -e UVICORN_WORKERS my-image
    

    You often won't want to run a dev server in a container. The Uvicorn documentation also has a Docker setup example that suggests uv run uvicorn ... as the main container command

    CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
    

    That's similar to the last Dockerfile fragment you show in that it uses uv run, but also similar to the first fragment in that it directly runs the application server without having a main function in your own code.