主要是利用到了 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/checkout@v2
- 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/checkout@v2
- 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()