首页 > 解决方案 > 使用手动 docker build 在 Heroku 上托管 API

问题描述

我想在 Heroku 免费层上托管一个小型 Web 应用程序。我docker compose用来在本地运行前端、后端 api 和 postgres 数据库。我正在关注 Heroku docs on deploy an existing docker image。但是,当我尝试访问 API 文档或尝试 curl API(两者都在本地工作)时,我收到错误

2021-01-31T15:19:23.679917+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/docs" host=apitest48398.herokuapp.com request_id=62ffd495-5977-4132-9ec7-d89abf5b1d8f fwd="77.100.21.140" dyno= connect= service= status=503 bytes= protocol=https
2021-01-31T15:19:24.465326+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/favicon.ico" host=apitest48398.herokuapp.com request_id=016de415-dc8e-4b0a-894e-8fad37ff7fee fwd="77.100.21.140" dyno= connect= service= status=503 bytes= protocol=https

注意我通过容器注册表进行部署,而不是通过将我的 git 存储库连接到 Heroku,因此既不是 aProcfile也不是heroku.yml文件。

以下是在一个最小示例中重现此行为的步骤。请注意,在实际示例中,我有多个 docker 文件,因此即使可以使用 部署此简单示例heroku container:push,我更喜欢自己构建图像,因此简单示例更能代表真实用例:

  1. fastAPI使用在名为的文件中创建应用程序main.py
    from fastapi import FastAPI
    
    app = FastAPI()
    
    
    @app.get("/")
    async def root():
        return {"message": "Hello World"}
    
  2. 创建一个requirements.txt文件:
    fastapi
    uvicorn
    
  3. 创建Dockerfile
    FROM python:3.7
    
    ENV PORT=$PORT
    
    COPY ./requirements.txt .
    RUN pip install -r requirements.txt
    
    COPY ./main.py .
    
    EXPOSE $PORT
    
    CMD uvicorn main:app --host 0.0.0.0 --port $PORT
    
    
  4. 构建图像
    docker build . -t herokubackendtest
    
  5. 登录 Heroku
    heroku container:login
    
  6. 创建 heroku 应用并将图像推送到 heroku(您需要使用不同的、唯一的 APP_NAME)
    export APP_NAME=apitest48398
    heroku create $APP_NAME
    docker tag herokubackendtest registry.heroku.com/$APP_NAME/api
    docker push registry.heroku.com/$APP_NAME/api
    
  7. 发布应用程序,放大测功机,检查进程是否正在运行,并检查日志以验证是否uvicorn正在运行:
    heroku container:release --app $APP_NAME api
    heroku ps:scale --app $APP_NAME api=1
    heroku ps --app $APP_NAME  # should show === api (Free): /bin/sh -c uvicorn\ main:app\ --host\ 0.0.0.0\ --port\ \$PORT (1)
    heroku logs --app $APP_NAME --tail
    

您应该在日志中看到以下内容(端口号会有所不同)

2021-01-31T15:17:39.806481+00:00 heroku[api.1]: Starting process with command `/bin/sh -c uvicorn\ main:app\ --host\ 0.0.0.0\ --port\ \16384`
2021-01-31T15:17:40.465132+00:00 heroku[api.1]: State changed from starting to up
2021-01-31T15:17:41.982857+00:00 app[api.1]: INFO:     Started server process [5]
2021-01-31T15:17:41.982918+00:00 app[api.1]: INFO:     Waiting for application startup.
2021-01-31T15:17:41.983162+00:00 app[api.1]: INFO:     Application startup complete.
2021-01-31T15:17:41.983529+00:00 app[api.1]: INFO:     Uvicorn running on http://0.0.0.0:16384 (Press CTRL+C to quit)

现在要对其进行测试,您应该能够在https://apitest48398.herokuapp.com/docsapitest48398$APP_NAME. 但相反,我在这个问题开始时发布的日志中出现错误,我看到一个页面显示:

Application error
An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details. You can do this from the Heroku CLI with the command
heroku logs --tail

在我的浏览器中。

我也希望curl https://apitest48398.herokuapp.com/返回我的hello worldjson,但它会返回一些带有错误的 HTML。我也尝试过使用 ports 443, 80,并且端口 uvicorn 在容器内运行(这个只是挂起直到超时)。

我想我错过了一些步骤,也许是 SSL?尽管我知道免费层上的任何 herokuapp.com 域都会自动启用此功能,但我看不到任何将 cert 和 pem 文件传递​​给 uvicorn 的方法。

谁能指出我如何解决这个问题的正确方向?

标签: dockerherokufastapiuvicorn

解决方案


使用Heroku Docker Registryweb指示的进程类型标记图像。在你的情况下

docker tag herokubackendtest registry.heroku.com/$APP_NAME/web
docker push registry.heroku.com/$APP_NAME/web
heroku container:release web --app $APP_NAME

推荐阅读