Reputation: 491
I have a FastAPI app that is working as expected when running locally, however, I get an 'Internal Server Error' when I try to run in a Docker container. Here's the code for my app:
from fastapi import FastAPI
from pydantic import BaseModel
import pandas as pd
from fbprophet import Prophet
class Data(BaseModel):
length: int
ds: list
y: list
model: str
changepoint: float = 0.5
daily: bool = False
weekly: bool = False
annual: bool = False
upper: float = None
lower: float = 0.0
national_holidays: str = None
app = FastAPI()
@app.post("/predict/")
async def create_item(data: Data):
# Create df from base model
df = pd.DataFrame(list(zip(data.ds, data.y)), columns =['ds', 'y'])
# Add the cap and floor to df for logistic model
if data.model == "logistic":
df['y'] = 10 - df['y']
df['cap'] = data.upper
df['floor'] = data.lower
# make basic prediction
m = Prophet(growth=data.model,
changepoint_prior_scale=data.changepoint,
weekly_seasonality=data.weekly,
daily_seasonality=data.daily,
yearly_seasonality=data.annual
)
# Add national holidays
if data.national_holidays is not None:
m.add_country_holidays(country_name=data.national_holidays)
# Fit data frame
m.fit(df)
# Create data frame for future
future = m.make_future_dataframe(periods=data.length)
# Add the cap and floor to future for logistic model
if data.model == "logistic":
future['cap'] = 6
future['floor'] = 1.5
# forecast
forecast = m.predict(future)
# Print values
print(list(forecast[['ds']].values))
# Return results
# {'ds': forecast[['ds']], 'yhat': forecast[['yhat']], 'yhat_lower': forecast[['yhat_lower']], 'yhat_upper': forecast[['yhat_upper']] }
return [forecast[['ds']], forecast[['yhat']], forecast[['yhat_lower']], forecast[['yhat_upper']]]
Which is working locally with uvicorn main:app
, but not when I build using this Dockerfile:
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
COPY ./app /app
RUN pip install -r requirements.txt
and start with
docker run -d --name mycontainer -p 8000:80 myimage
I'm seeing Internal Server Error
in Postman. Is there something wrong with my dockerfile or docker commands? Or else how do I debug this?
Upvotes: 12
Views: 14367
Reputation: 990
When you run a FastAPI app inside a Docker container and try to access it from outside the container (like from your host machine or another container), you might run into an 'Internal Server Error' or 'Error: read ECONNRESET' even if the app works perfectly fine on your local machine. This issue often comes due to how the app is configured to handle network connections.
In the provided code snippet, the settings.host
value tells us the address the app will bind to. If settings.host
is set to 127.0.0.1
, the app will only accept connections from within the container itself. This is because 127.0.0.1
is the loopback address, which means it's only accessible from the same container.
Docker containers have their own isolated network environments, and each container has its own localhost
(127.0.0.1
) that isn't shared with the host machine or other containers. So, if you bind your app to 127.0.0.1
, it won't be accessible from outside the container.
To make your Fastapi app accessible from outside the container, you need to set settings.host
to 0.0.0.0
. This tells the app to listen on all available network interfaces, including the one Docker uses to route external traffic to the container.
Fix: Update your code to ensure settings.host
is set to 0.0.0.0
:
uvicorn.run(
"exg_platform.web.application:get_app",
workers=settings.workers_count,
host="0.0.0.0", # Bind to all interfaces
port=settings.port,
reload=settings.reload,
log_level=settings.log_level.lower(),
factory=True,
)
Upvotes: 1
Reputation: 596
I had the same problem because --port 8000
was missing in
command: uvicorn main:app --host 0.0.0.0 --port 8000
Upvotes: 11
Reputation: 2014
There are a number of possible issues here.
When running in a container, you need to tell Uvicorn to not care about the incoming host IP with option --host 0.0.0.0
You have not specified the command executed when the image runs. Best to make this clear in the dockerfile e.g. CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Make sure when you run the image you map the ports correctly. From what you have given you are expecting the service in the container to be listening on port 80, that is OK but the default for uvicorn is 8000 (see point 2 for explicitly setting port).
Upvotes: 20
Reputation: 824
Run the docker without the -d
parameter and you'll get more clues about it. If I were to guess, I might say that you're missing some python requirement.
Upvotes: 7