用 GitHub Actions 把项目部署到 Heroku

文章目录
  1. 1. 使用 Heroku 方式部署 Flask 应用
    1. 1.1. Actions 配置文件
      1. 1.1.1. 项目配置
        1. 1.1.1.1. Python:以 Flask 应用程序为例
        2. 1.1.1.2. requirements.txt
        3. 1.1.1.3. Procfile
        4. 1.1.1.4. runtime.txt
    2. 1.2. FAQs
  2. 2. 使用 Docker 方式部署 FastAPI 服务
    1. 2.1. Github Actions 脚本
    2. 2.2. Dockerfile
    3. 2.3. 目录结构

主要是利用到了 Actions Marketplace 里面的 Deploy to Heroku 项目。

使用 Heroku 方式部署 Flask 应用

Actions 配置文件

在项目 .github/workflows/ 下创建 heroku.yml ,并写入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: Push Container to Heroku

on:
push:
branches:
- master

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- uses: akhileshns/[email protected]
with:
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
heroku_app_name: "APPNAME" #Must be unique in Heroku (APPNAME.herokuapp.com)
heroku_email: ""
branch: "master" #OPTIONAL and DEFAULT - 'HEAD' (a.k.a your current branch)
dontuseforce: false #OPTIONAL and DEFAULT - false
usedocker: false #OPTIONAL and DEFAULT - false

然后在项目的环境变量中设置 HEROKU_API_KEY ,这玩意儿在 Heroku 的 Account Settings 页可以找到,形如:00000aa0-000a-00a0-0a0a-00a00a00a0a0

注意,现在默认的分支名变成 main 了,Actions 仓库也有更新,请酌情修改。

项目配置

这一节补充一下为把项目部署到 Heroku,要对项目进行的一些修改。

Python:以 Flask 应用程序为例

主要需要三份文件:requirements.txtProcfileruntime.txt

requirements.txt
1
pip freeze > requirements.txt

记得先装上 Gunicorn。

Procfile

这是 Heroku App 的启动脚本。

如果 app.py 在根目录:

1
web: gunicorn app:app --log-file -

如果 app1.py 在名为 projectname 的子文件夹下:

1
web: gunicorn --pythonpath projectname app1:app2 --log-file -

注:app1是 app1.py,app2是 app1.py 内一个指向 Flask 实例的变量,一般来讲就是

1
app2 = Flask(__name__)
runtime.txt

指定 Heroku App 所使用的 Python 版本。最近(2020 年 5 月)一般是:

1
python-3.8.2

请参阅 Specifying a Python Runtime - Heroku Dev Center

FAQs

Q1:为什么你 TM 不用 Heroku 的 Connect to GitHub 呢?

A1:因为这样搞就可以一个 GitHub 账号对应多个 Heroku 账号了嘛。但其实我也没试过直接走 OAuth 可不可以一对多。

使用 Docker 方式部署 FastAPI 服务

本段落于 2022 年寒假更新。

这个假期彻底地把玩了一下 Docker,不由得所有服务都用 Docker 托管。而且也遇到了一些纯 Heroku 方式无法解决的需求(某个服务需要用到 apt-get 安装的一个依赖),因此不得不使用 Docker 方法部署服务。

Github Actions 脚本

.github/workflows/heroku.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name: Push Container to Heroku

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- uses: akhileshns/[email protected] # This is the action
with:
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
heroku_app_name: ${{secrets.HEROKU_APP_NAME}}
heroku_email: ${{secrets.HEROKU_EMAIL}}
usedocker: true

Dockerfile

使用 Docker 方式部署时,根目录下不再需要 Procfile 和 runtime.txt 等 Heroku 特有的文件了,就是一个纯纯的 Docker 仓库的格式即可。

1
2
3
4
5
6
7
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9-slim

RUN apt-get update -y && apt-get install -y 某个软件

COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./app /app

目录结构

相信你已经注意到,Dockerfile 中的目录结构有点特别,这个项目的目录结构是这样的:

1
2
3
4
5
6
7
project/
.github/
app/
main.py
Dockerfile
requirements.txt
...

其中 main.py 里面的 FastAPI 初始化对象一定要是:

1
app = FastAPI()

当然,最佳实践是这样的:

1
2
3
4
5
env = os.getenv('env')
if env != 'develop':
app = FastAPI(docs_url=None, redoc_url=None)
else:
app = FastAPI()