【问题标题】:Host an API on Heroku using a manual docker build使用手动 docker build 在 Heroku 上托管 API
【发布时间】:2026-01-11 18:20:03
【问题描述】:

我想在 Heroku 免费层上托管一个小型 Web 应用程序。我正在使用docker compose 在本地运行前端、后端 api 和 postgres 数据库。我正在关注deploying an existing docker image 上的 Heroku 文档。但是,当我尝试访问 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,因此既不是 Procfile,也不是 heroku.yml 文件。

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

  1. 在名为main.py 的文件中使用fastAPI 创建应用程序:
    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. 发布应用程序,放大 dyno,检查进程是否正在运行,并检查日志以验证 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/docs 看到 openAPI(swagger)文档,其中 apitest48398 是您的 $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 world json,但它会返回一些带有错误的 HTML。我也尝试过使用端口44380,并且端口 uvicorn 在容器内运行(这个端口一直挂到超时)。

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

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

【问题讨论】:

    标签: docker heroku fastapi uvicorn


    【解决方案1】:

    使用web 进程类型标记图像,如Heroku Docker Registry 所示。你的情况

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

    【讨论】:

    • 天啊,我不敢相信就是这样。即使从您的链接中,我也不清楚进程类型需要具有特定名称web,哈哈。我认为这只是一个你可以选择的名字。那么这是否意味着如果我同时拥有一个前端网页和一个后端 api 服务,我需要将它们分开,因为它们都需要被称为 web?
    • web 是进程类型,这意味着它将接受 HTTP 请求(与在后台工作的工作人员不同)。如果您的前端通过 HTTP 调用后端,则需要 2 个网络测功机
    • 你能在一个 Heroku 应用中拥有 2 个网络测功机吗?我假设不是基于您答案中的代码,因为无法区分它们。 2 个 web dyno 是否意味着两个 heroku 应用,每个应用都有一个 web dyno?
    • 是的,很抱歉造成混乱。一个应用程序需要一个测功机。如果您将前端和后端打包在一个应用程序中,那么您需要一个 web dyno。
    最近更新 更多