Reputation: 31
I have a FastAPI app that works well when I launch it as a script. Unfortunately, I can't get access to my app when I'm using Docker and docker-compose.
I can't reach it by 127.0.0.1:80 or 127.0.0.1:8000. At the same time, I'm using configs that worked well for me with another project but with Flask. Can someone say what I did wrong?
My project structure
├── projectname
│ ├── src
│ └── app.py
├── Dockerfile
├── Makefile
├── docker-compose.yaml
└── requirements.txt
This is my app.py
import uvicorn
from typing import Any
from fastapi import FastAPI, HTTPException
from motor.motor_asyncio import AsyncIOMotorClient
from src.fastapi_pagination.ext.motor import paginate
from src.fastapi_pagination import Page, add_pagination
from src.settings import DB_CONNECTION
from src.models import PropertyModel, LogModel, LogDetailsModel
app = FastAPI()
client: AsyncIOMotorClient
@app.on_event("startup")
async def on_startup() -> None:
global client
client = AsyncIOMotorClient(DB_CONNECTION)
@app.get("/api/property/{property_id}", response_description="Get a single property", response_model=PropertyModel)
async def show_property(property_id: str):
if (result := await client.property_listing.properties.find_one({"property_id": property_id})) is not None:
return result
raise HTTPException(status_code=404, detail=f"Property {property_id} not found")
@app.get("/api/properties", response_description="Get property list", response_model=Page[PropertyModel])
async def show_properties() -> Any:
sort = [('property_new', -1), ('property_date_updated', -1)]
if (result := await paginate(client.property_listing.properties, sort_query=sort)) is not None:
return result
else:
raise HTTPException(status_code=404, detail=f"No properties on this page")
add_pagination(app)
if __name__ == "__main__":
uvicorn.run("app:app", port=8000, host='0.0.0.0')
My Dcokerfile
FROM python:3.8.3-alpine3.12
COPY ["requirements.txt", "/app/"]
RUN apk add --update --no-cache make bash libpq
RUN apk add --no-cache --virtual build \
build-base \
musl-dev \
libffi-dev \
openssl-dev \
&& pip install --no-cache-dir -r /app/requirements.txt \
&& apk del build
WORKDIR /app
EXPOSE 8000
My docker-compose.yaml
file
version: '3.8'
services:
app_launch:
build: .
image: fastapi-service:dev
ports:
- "8000:8000"
volumes:
- .:/app
My Makefile
### Compose shortcuts
up:
docker-compose up -d
down:
docker-compose down
build:
docker-compose build
sh:
docker-compose run -p 8000:8000 --rm app_launch bash
logs:
docker-compose logs -f
### Project shortcuts
fast_api:
docker-compose run --rm app_launch python src/app.py
fast_api_app:
docker-compose run --rm app_launch uvicorn src.app:app --proxy-headers --host 0.0.0.0 --port 8000
When I use make build
image builds well. make fast_api
and make fast_api_app
both work well. I have an output like that:
docker-compose run --rm app_launch python src/app.py
Creating fast_test_app_launch_run ... done
INFO: Started server process [1]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
But I still can't reach my app from the browser. Could someone explain how to fix it?
Upvotes: 3
Views: 5900
Reputation: 158647
docker-compose run
by default does not publish ports:
from the container. It's not intended to be the way you launch your main application; instead, it's there to run one-off commands like database migrations that require most of the container setup but can run alongside the application proper.
Probably the best way to address this is to set a standard CMD
in your Dockerfile, so the container knows what to do:
CMD uvicorn src.app:app --proxy-headers --host 0.0.0.0 --port 8000
Then you don't need docker-compose run
or any of the other variants you show here; just running docker-compose up
will start your application.
docker-compose run
also has a --service-ports
option that will make it publish the container's ports:
anyways, if that's the problem you're running into, but this wouldn't be my preferred way to launch a service container.
Upvotes: 4