I am trying to deploy a fast API todo app onto Heroku by container registry. When I build the docker image and run it in my local. I am able to access my swagger in http://localhost:8001/docs. But I am not able to access when I deployed to heroku and I am getting this error :
Error: Exec format error
Here is my main.py
from fastapi import FastAPI,Depends
from fastapi.middleware.cors import CORSMiddleware
from db.db import get_db
from bson.objectid import ObjectId
from models.todo import Todo
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
def root():
return {"message": "Hello World"}
@app.get("/api/todo",response_model=Todo)
async def get_todo(db=Depends(get_db)):
data = await db.todo.find()
result: Todo = Todo(**data)
return result
@app.get("/api/todo/{todo_id}",response_model=Todo)
async def get_todo(todo_id: str,db=Depends(get_db)):
data = await db.todo.find_one({"_id": ObjectId(todo_id)})
result: Todo = Todo(**data)
return result
@app.post("/api/todo")
async def create_todo(db=Depends(get_db),payload:Todo=None):
result = await db.todo.insert_one(payload.dict())
return {"message": "Todo created successfully", "todo_id": str(result.inserted_id)}
@app.put("/api/todo/{todo_id}")
async def update_todo(todo_id: str,db=Depends(get_db),payload:Todo=None):
result = db.todo.update_one({"_id": ObjectId(todo_id)}, {"$set": payload.dict()})
return {"message": "Todo updated successfully", "todo_id": str(result.inserted_id)}
@app.delete("/api/todo/{todo_id}")
async def delete_todo(todo_id: str,db=Depends(get_db)):
result = db.todo.delete_one({"_id": ObjectId(todo_id)})
return {"message": "Todo deleted successfully", "todo_id": str(result.inserted_id)}
and my Dockerfile
FROM python:3.8
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
# EXPOSE 8000
RUN chmod +x run.sh
ENTRYPOINT ["/bin/bash", "-c" ,"./run.sh"]
I tried using CMD instead of ENTERYPOINT did not work. I also tried using
CMD ["uvicorn", "main:app","--proxy-headers", "--host", "${HOST}", "--port", "${PORT}"]
run.sh
#!/bin/sh
export APP_MODULE=${APP_MODULE-main:app}
export HOST=${HOST:-0.0.0.0}
export PORT=${PORT:-8001}
# run gunicorn
gunicorn --bind $HOST:$PORT "$APP_MODULE" -k uvicorn.workers.UvicornWorker
requirements.txt
fastapi
uvicorn
motor
gunicorn
2
Answers
You are building locally (Mac?) the image on a platform which is not compatible with Heroku (linux/amd64)
Set the platform as you build/push the image to the Heroku registry
You can also set the
DOCKER_DEFAULT_PLATFORM
as env variables (to avoid setting it everytime – note all images would be linux/amd64)Try using a heroku.yml file instead of
CMD
to start the server when it’s deployed to heroku.I was unable to connect to my server until I switched to the
heroku.yml
.