db867dcbe5
Deploy to Staging / deploy (push) Has been cancelled
Conflict detector / main (push) Has been cancelled
Lint Backend / lint-backend (push) Has been cancelled
Playwright Tests / changes (push) Has been cancelled
Test Backend / test-backend (push) Has been cancelled
Test Docker Compose / test-docker-compose (push) Has been cancelled
Playwright Tests / test-playwright (1, 4) (push) Has been cancelled
Playwright Tests / test-playwright (2, 4) (push) Has been cancelled
Playwright Tests / test-playwright (3, 4) (push) Has been cancelled
Playwright Tests / test-playwright (4, 4) (push) Has been cancelled
Playwright Tests / merge-playwright-reports (push) Has been cancelled
Playwright Tests / alls-green-playwright (push) Has been cancelled
Issue Manager / issue-manager (push) Has been cancelled
317 lines
10 KiB
Markdown
317 lines
10 KiB
Markdown
# FastAPI 项目 - 部署(Deployment)
|
||
|
||
你可以使用 Docker Compose 将本项目部署到远程服务器。
|
||
|
||
本项目假定你已经有一个 Traefik 代理,用于处理对外的 HTTP/HTTPS 流量以及证书管理。
|
||
|
||
你可以使用 CI/CD(持续集成与持续部署)系统自动部署,本项目已经提供了 GitHub Actions 的示例配置。
|
||
|
||
在此之前,你需要完成一些基础配置。🤓
|
||
|
||
## 部署前准备
|
||
|
||
* 准备一台可访问的远程服务器。
|
||
* 将你的域名 DNS 记录解析到该服务器的 IP。
|
||
* 为该域名配置通配符子域名(Wildcard),例如 `*.fastapi-project.example.com`,以便为不同服务使用不同子域名,如 `dashboard.fastapi-project.example.com`、`api.fastapi-project.example.com`、`traefik.fastapi-project.example.com`、`adminer.fastapi-project.example.com` 等;同时也便于配置 `staging` 环境,比如 `dashboard.staging.fastapi-project.example.com`、`adminer.staging.fastapi-project.example.com` 等。
|
||
* 在远程服务器上安装并配置 [Docker](https://docs.docker.com/engine/install/)(Docker Engine,而非 Docker Desktop)。
|
||
|
||
## 公共 Traefik
|
||
|
||
我们需要一个 Traefik 代理来处理外部请求以及 HTTPS 证书。
|
||
|
||
下面的步骤只需执行一次。
|
||
|
||
### Traefik 的 Docker Compose
|
||
|
||
* 在远程服务器上创建一个目录,用来存放 Traefik 的 Docker Compose 文件:
|
||
|
||
```bash
|
||
mkdir -p /root/code/traefik-public/
|
||
```
|
||
|
||
在本地终端中使用 `rsync` 将 Traefik 的 Docker Compose 文件拷贝到服务器:
|
||
|
||
```bash
|
||
rsync -a docker-compose.traefik.yml root@your-server.example.com:/root/code/traefik-public/
|
||
```
|
||
|
||
### Traefik 公共网络
|
||
|
||
Traefik 会期望有一个名为 `traefik-public` 的 Docker “公共网络”,用来与各个应用 stack 通信。
|
||
|
||
通过这种方式,可以用一个公共 Traefik 代理对外处理 HTTP/HTTPS 流量,其后可以挂载一个或多个不同域名的应用 stack,即便它们都在同一台物理服务器上。
|
||
|
||
在远程服务器中创建该网络:
|
||
|
||
```bash
|
||
docker network create traefik-public
|
||
```
|
||
|
||
### Traefik 环境变量
|
||
|
||
Traefik 的 Docker Compose 文件在启动前需要若干环境变量,你可以在远程服务器终端中通过以下命令设置:
|
||
|
||
* 为 HTTP Basic Auth 创建用户名,例如:
|
||
|
||
```bash
|
||
export USERNAME=admin
|
||
```
|
||
|
||
* 创建 Basic Auth 密码对应的环境变量,例如:
|
||
|
||
```bash
|
||
export PASSWORD=changethis
|
||
```
|
||
|
||
* 使用 openssl 生成该密码的哈希值并保存到环境变量中:
|
||
|
||
```bash
|
||
export HASHED_PASSWORD=$(openssl passwd -apr1 $PASSWORD)
|
||
```
|
||
|
||
可以通过打印检查哈希是否已生成:
|
||
|
||
```bash
|
||
echo $HASHED_PASSWORD
|
||
```
|
||
|
||
* 创建保存服务器主域名的环境变量,例如:
|
||
|
||
```bash
|
||
export DOMAIN=fastapi-project.example.com
|
||
```
|
||
|
||
* 创建保存 Let's Encrypt 邮箱的环境变量,例如:
|
||
|
||
```bash
|
||
export EMAIL=admin@example.com
|
||
```
|
||
|
||
**注意**:邮箱不能是 `@example.com` 这样的占位域名,需要使用真实邮箱。
|
||
|
||
### 启动 Traefik Docker Compose
|
||
|
||
在远程服务器上进入存放 Traefik Docker Compose 文件的目录:
|
||
|
||
```bash
|
||
cd /root/code/traefik-public/
|
||
```
|
||
|
||
在环境变量已经设置、`docker-compose.traefik.yml` 已就位的情况下,启动 Traefik:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.traefik.yml up -d
|
||
```
|
||
|
||
## 部署 FastAPI 项目
|
||
|
||
在 Traefik 准备好之后,就可以使用 Docker Compose 部署 FastAPI 项目。
|
||
|
||
**提示**:你也可以直接跳到后面的「使用 GitHub Actions 持续部署」部分。
|
||
|
||
## 环境变量
|
||
|
||
在部署前,需要设置若干环境变量。
|
||
|
||
设置 `ENVIRONMENT`,默认是 `local`(开发环境),部署到服务器时可以设置为 `staging` 或 `production`,例如:
|
||
|
||
```bash
|
||
export ENVIRONMENT=production
|
||
```
|
||
|
||
设置 `DOMAIN`,本地默认是 `localhost`,在部署时应改为你的实际域名,例如:
|
||
|
||
```bash
|
||
export DOMAIN=fastapi-project.example.com
|
||
```
|
||
|
||
你还可以设置以下变量:
|
||
|
||
* `PROJECT_NAME`:项目名称,用于 API 文档及邮件内容中展示。
|
||
* `STACK_NAME`:在 Docker Compose 中使用的 stack 名称,也用于标签与项目名。该值在 `staging`、`production` 等环境中应各不相同。一个常见做法是将域名中的点替换为短横线,例如 `fastapi-project-example-com` 与 `staging-fastapi-project-example-com`。
|
||
* `BACKEND_CORS_ORIGINS`:允许的 CORS 源列表,使用逗号分隔。
|
||
* `SECRET_KEY`:FastAPI 项目的密钥,用于签发 token 等安全相关操作。
|
||
* `FIRST_SUPERUSER`:首个超级用户的邮箱地址,该用户可以创建其他用户。
|
||
* `FIRST_SUPERUSER_PASSWORD`:首个超级用户的密码。
|
||
* `SMTP_HOST`:SMTP 服务器地址,用于发邮件(如 Mailgun、Sparkpost、Sendgrid 等提供的地址)。
|
||
* `SMTP_USER`:SMTP 用户名。
|
||
* `SMTP_PASSWORD`:SMTP 密码。
|
||
* `EMAILS_FROM_EMAIL`:发件邮箱地址。
|
||
* `POSTGRES_SERVER`:PostgreSQL 服务器主机名。使用 Docker Compose 时可以保持默认值 `db`,除非你改为使用第三方数据库服务。
|
||
* `POSTGRES_PORT`:PostgreSQL 端口,通常保持默认即可。
|
||
* `POSTGRES_PASSWORD`:PostgreSQL 密码。
|
||
* `POSTGRES_USER`:PostgreSQL 用户名,一般使用默认值即可。
|
||
* `POSTGRES_DB`:本应用使用的数据库名称,默认 `app`。
|
||
* `SENTRY_DSN`:如果接入了 Sentry,这里填入 DSN。
|
||
|
||
## GitHub Actions 环境变量
|
||
|
||
有一些环境变量只在 GitHub Actions 中使用,可以按需配置:
|
||
|
||
* `LATEST_CHANGES`:用于 [latest-changes](https://github.com/tiangolo/latest-changes) GitHub Action,根据合并的 PR 自动生成发布日志。它需要一个个人访问令牌(PAT),具体可见其文档。
|
||
* `SMOKESHOW_AUTH_KEY`:用于 [Smokeshow](https://github.com/samuelcolvin/smokeshow) 发布测试覆盖率报告,同样需要按其说明生成一个(免费的)密钥。
|
||
|
||
### 生成密钥
|
||
|
||
`.env` 文件中的一些环境变量默认为 `changethis`,需要改为真正的随机密钥。
|
||
|
||
可以使用下面的命令生成密钥:
|
||
|
||
```bash
|
||
python -c "import secrets; print(secrets.token_urlsafe(32))"
|
||
```
|
||
|
||
复制输出内容并用作密码 / 密钥;需要多个密钥时多执行几次即可。
|
||
|
||
### 使用 Docker Compose 部署
|
||
|
||
环境变量准备就绪后,可以使用 Docker Compose 部署:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.yml up -d
|
||
```
|
||
|
||
在生产环境中,一般不希望加载 `docker-compose.override.yml` 中的开发用覆盖配置,因此这里显式指定只使用 `docker-compose.yml`。
|
||
|
||
## 持续部署(CD)
|
||
|
||
你可以使用 GitHub Actions 自动部署你的项目。😎
|
||
|
||
可以为多个环境配置不同的部署流程。
|
||
|
||
本项目中已经预置了 `staging` 与 `production` 两个环境。🚀
|
||
|
||
### 安装 GitHub Actions Runner
|
||
|
||
* 在远程服务器上为 GitHub Actions 创建一个用户,例如:
|
||
|
||
```bash
|
||
sudo adduser github
|
||
```
|
||
|
||
* 为 `github` 用户添加 Docker 权限:
|
||
|
||
```bash
|
||
sudo usermod -aG docker github
|
||
```
|
||
|
||
* 临时切换为 `github` 用户:
|
||
|
||
```bash
|
||
sudo su - github
|
||
```
|
||
|
||
* 进入 `github` 用户的 home 目录:
|
||
|
||
```bash
|
||
cd
|
||
```
|
||
|
||
* 按照官方文档安装 GitHub Action 自托管 Runner:
|
||
<https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-a-repository>
|
||
|
||
* 在安装过程中,当被询问标签(labels)时,为 Runner 添加对应环境的标签,例如 `production`;也可以在后续再补充标签。
|
||
|
||
安装完成后,官方文档会让你手动运行一个命令以启动 Runner。但一旦你断开终端连接或进程退出,Runner 就会停止。
|
||
|
||
为了确保服务器重启后 Runner 仍能自动运行,建议将其安装为服务。具体步骤如下:
|
||
|
||
* 从 `github` 用户退出,回到之前的用户:
|
||
|
||
```bash
|
||
exit
|
||
```
|
||
|
||
此时你会回到之前的用户及其当前目录。
|
||
|
||
* 在能访问 `github` 用户 home 目录之前,你需要切换成 `root` 用户(如果已经是则可略过):
|
||
|
||
```bash
|
||
sudo su
|
||
```
|
||
|
||
* 在 `root` 用户下,进入 `github` 用户 home 下的 `actions-runner` 目录:
|
||
|
||
```bash
|
||
cd /home/github/actions-runner
|
||
```
|
||
|
||
* 安装 Runner 为服务,并指定服务用户为 `github`:
|
||
|
||
```bash
|
||
./svc.sh install github
|
||
```
|
||
|
||
* 启动该服务:
|
||
|
||
```bash
|
||
./svc.sh start
|
||
```
|
||
|
||
* 查看服务状态:
|
||
|
||
```bash
|
||
./svc.sh status
|
||
```
|
||
|
||
更多细节可参考官方文档:
|
||
「Configuring the self-hosted runner application as a service」
|
||
<https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/configuring-the-self-hosted-runner-application-as-a-service>
|
||
|
||
### 配置 Secrets
|
||
|
||
在 GitHub 仓库中,为部署需要的环境变量配置 Secrets,包括前面提到的 `SECRET_KEY` 等。可参考官方文档:
|
||
「Using secrets in GitHub Actions」
|
||
<https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository>
|
||
|
||
当前的 GitHub Actions 工作流期望存在以下 Secrets:
|
||
|
||
* `DOMAIN_PRODUCTION`
|
||
* `DOMAIN_STAGING`
|
||
* `STACK_NAME_PRODUCTION`
|
||
* `STACK_NAME_STAGING`
|
||
* `EMAILS_FROM_EMAIL`
|
||
* `FIRST_SUPERUSER`
|
||
* `FIRST_SUPERUSER_PASSWORD`
|
||
* `POSTGRES_PASSWORD`
|
||
* `SECRET_KEY`
|
||
* `LATEST_CHANGES`
|
||
* `SMOKESHOW_AUTH_KEY`
|
||
|
||
## GitHub Actions 部署工作流
|
||
|
||
在 `.github/workflows` 目录中已经包含了一些用于部署到不同环境(基于 Runner 标签)的 GitHub Actions 工作流:
|
||
|
||
* `staging`:在推送(或合并)到 `master` 分支后触发。
|
||
* `production`:在发布 Release 后触发。
|
||
|
||
如果你需要更多环境,可以以上述工作流为模板进行扩展。
|
||
|
||
## URLs
|
||
|
||
下面示例中出现的 `fastapi-project.example.com` 请替换为你自己的域名。
|
||
|
||
### 主 Traefik 控制台
|
||
|
||
Traefik UI:`https://traefik.fastapi-project.example.com`
|
||
|
||
### 生产环境(Production)
|
||
|
||
前端:`https://dashboard.fastapi-project.example.com`
|
||
|
||
后端 API 文档:`https://api.fastapi-project.example.com/docs`
|
||
|
||
后端 API 基础地址:`https://api.fastapi-project.example.com`
|
||
|
||
Adminer:`https://adminer.fastapi-project.example.com`
|
||
|
||
### 预发布环境(Staging)
|
||
|
||
前端:`https://dashboard.staging.fastapi-project.example.com`
|
||
|
||
后端 API 文档:`https://api.staging.fastapi-project.example.com/docs`
|
||
|
||
后端 API 基础地址:`https://api.staging.fastapi-project.example.com`
|
||
|
||
Adminer:`https://adminer.staging.fastapi-project.example.com`
|