The Problem
I am deploying a Docker image running FastAPI to Heroku using the Docker Container Registry deployment method. When I deploy the container I get the following logs when I run heroku logs --app <app-name> --tail
2024-06-03T20:57:32.222808+00:00 app[api]: Release v29 created by user [email protected]
2024-06-03T20:57:32.222808+00:00 app[api]: Deployed web (228f5e77d4e2) by user [email protected]
2024-06-03T20:57:45.637479+00:00 heroku[web.1]: Starting process with command `/bin/sh -c "./start.sh ${PORT}"`
2024-06-03T20:57:46.235100+00:00 heroku[web.1]: Process exited with status 127
2024-06-03T20:57:46.185240+00:00 app[web.1]: /bin/sh: 1: ./start.sh 53182: not found
2024-06-03T20:57:46.255899+00:00 heroku[web.1]: State changed from starting to crashed
In the Heroku UI I can see the command for starting a web
process is web /bin/sh -c "./start.sh ${PORT}"
which is correct as that command works locally. I’ve even exec’d into the container and run /bin/sh -c "./start.sh <port>"
to verify it will work, and it does (meaning I can hit any and all of my API endpoints and get the expected results).
The Details
Dockerfile
FROM node:21 as ui-build
ENV PORT $PORT
WORKDIR /opt/ui
COPY ui .
RUN npm ci && npm run build
FROM python:3.11 as final-build
WORKDIR /opt/app
COPY --from=ui-build /opt/ui/build ./ui/build
COPY server server
RUN cd server && pip install -r requirements.txt
# Apparently Heroku doesn't respect the EXPOSE directive.
EXPOSE $PORT
WORKDIR /opt/app/server
COPY ./start.sh .
# Not sure why these commands are not working but the start.sh script seems to be going in the right direction.
# ENTRYPOINT [ "uvicorn", "api.app:app" ]
# CMD [ "--host", "0.0.0.0", "--port", $PORT ]
CMD "./start.sh ${PORT}"
I’m using the gonuit/heroku-docker-deploy Github Action to build and push the docker image to Heroku’s container registry. Here is how I use the action in my workflow.
name: Build and Push Image
on:
push:
branches:
- main
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and Push to Heroku
uses: gonuit/[email protected]
with:
email: [email protected]
heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
heroku_app_name: <app-name>
The Links
These are some of the links I’ve used to come up with code I currently have but neither has worked for me.
- https://akshaykhatale.medium.com/deploy-fastapi-on-heroku-using-docker-container-a920f839de9b
- How to deploy fast api as a backend in docker container to heroku
This final link is the official Heroku Docs on deploying w/ Docker Container Registry which to the best of my knowledge I’ve implemented identically.
- https://devcenter.heroku.com/articles/container-registry-and-runtime
The Solution
An ideal solution for me would be able to deploy my application using Docker, and Github Actions. If I need to add a Procfile or Heroku.yml file to the application I’m alright with that it just seems to be something that’s not needed for the deployment method I’m using.