Files
ftb-project-management/docs/deployment.md
72a59f125c docs(ops): 补齐生产 runbook 和 readiness 清单
- 新增迁移回滚、AppData 退场、小宝后台任务 runbook\n- 新增生产 readiness 证据清单和 runbook placeholder 扫描\n- 更新部署文档与路线图到 V2.8 运维闭环阶段\n\nCo-Authored-By: GPT-5 Codex <codex@openai.com>
2026-07-08 16:28:02 +08:00

346 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 部署指南
本文档覆盖三种部署方式:
- 本地开发:前端、后端直接用 pnpm 跑PostgreSQL 和 Redis 用 `docker-compose.yml` 启动。
- 本地服务器部署:一台本机或局域网服务器用 `docker-compose.local.yml` 跑完整 Web、Server、PostgreSQL、Redis、Nginx。
- 云服务器生产:所有服务用 `docker-compose.prod.yml` 编排Nginx 对外暴露 HTTP业务数据写入 PostgreSQL volumeAI 配置文件写入 server volume。
## 本地开发部署
```bash
pnpm install
cp apps/server/.env.example apps/server/.env
docker compose up -d
pnpm db:migrate
pnpm dev
```
访问地址:
- Web: `http://localhost:3000`
- API: `http://localhost:3001/api/v1`
- API 健康探测:`http://localhost:3001/api/v1/config/ai`
## 本地服务器部署
本地服务器部署适合这些场景:
- 在自己的电脑上用接近生产的方式跑完整系统。
- 在办公室内网或测试机上给同事访问。
- 不想安装 Node/pnpm 到目标机器,只想用 Docker Compose 管理全栈服务。
它不同于“本地开发”:不会用 `pnpm dev`,而是构建生产镜像并通过 Nginx 统一入口访问。
### 1. 准备配置
```bash
cp .env.local-server.example .env.local-server
```
默认访问地址是:
```text
http://localhost:8080
```
如果要给局域网其他人访问,修改 `.env.local-server`
```env
LOCAL_ACCESS_HOST=192.168.1.50
NEXTAUTH_URL=http://192.168.1.50:8080
```
其中 `192.168.1.50` 换成这台机器在局域网里的 IP。`NEXT_PUBLIC_API_URL` 保持 `/api/v1`,让浏览器通过同一个 Nginx 入口访问后端。
### 2. 校验并启动
```bash
pnpm deploy:verify
pnpm deploy:local:build
pnpm deploy:local:up
```
首次启动后执行数据库 migration
```bash
docker compose --env-file .env.local-server -f docker-compose.local.yml exec server pnpm --filter server db:deploy
```
检查服务:
```bash
docker compose --env-file .env.local-server -f docker-compose.local.yml ps
curl http://localhost:8080/api/v1/config/ai
```
停止本地服务器部署:
```bash
pnpm deploy:local:down
```
本地服务器部署使用独立 volume
- `local_postgres_data`
- `local_redis_data`
- `local_server_data`
这些 volume 与云服务器生产部署的 `postgres_data``redis_data``server_data` 分开,避免本机测试数据和生产数据混在一起。
## 云服务器生产部署
### 1. 准备服务器
推荐一台 2 核 4G 以上 Linux 云服务器,并安装:
- Docker Engine
- Docker Compose v2
- Git
开放 80 端口。如果 HTTPS 由云厂商负载均衡、CDN 或宝塔/Nginx 外层托管,则在外层终止 TLS 后转发到本机 80。
### 2. 准备配置
```bash
cp .env.production.example .env.production
```
必须修改这些值:
- `POSTGRES_PASSWORD`:强密码。
- `DATABASE_URL`:密码要与 `POSTGRES_PASSWORD` 一致,主机保持 `postgres`
- `SERVER_NAME`:你的域名,例如 `pm.example.com`
- `NEXTAUTH_URL`:正式访问地址,例如 `https://pm.example.com`
- `NEXTAUTH_SECRET`:随机长密钥。
- `NEXT_PUBLIC_API_URL`:同域部署保持 `/api/v1`;如果前后端分域,填完整 API 地址。
- `ANTHROPIC_API_KEY`:可先留空或占位,后续也可以在 `/admin/ai-config` 页面配置。
### 3. 校验部署文件
```bash
pnpm deploy:verify
```
该命令会检查 `Dockerfile.web``Dockerfile.server``docker-compose.prod.yml``docker-compose.local.yml`、Nginx 模板、env 示例和本文档是否齐全。
### 4. 构建并启动
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml build
docker compose --env-file .env.production -f docker-compose.prod.yml up -d
```
首次启动后执行数据库迁移:
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml exec server pnpm --filter server db:deploy
```
然后检查服务状态:
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml ps
curl http://localhost/api/v1/config/ai
```
## 全自动生产发布(推荐)
生产环境推荐走 `.github/workflows/deploy-production.yml`,不再要求部署侧手工执行 `docker compose build` 或手工判断是否需要 `up`
GitHub 仓库需要配置这些 Secrets
- `PROD_HOST`:生产服务器地址。
- `PROD_USER`SSH 用户。
- `PROD_SSH_KEY`SSH 私钥。
- `PROD_APP_DIR`:服务器上的项目目录。
- `GHCR_READ_TOKEN`可选。GHCR 镜像为私有包时,用于服务器 `docker login ghcr.io` 拉镜像。
服务器首次准备仍然需要完成一次:
```bash
git clone <repo-url> ftb-project-management
cd ftb-project-management
cp .env.production.example .env.production
```
然后按实际环境改好 `.env.production` 里的数据库密码、域名、`NEXTAUTH_SECRET`、AI key 等。`APP_VERSION``APP_BUILD_TIME``WEB_IMAGE``SERVER_IMAGE` 会由 GitHub Actions 在每次发布时自动更新。
之后只要代码合并或 push 到 `master`Actions 会自动执行:
1. 用当前 commit SHA 构建 `web``server` Docker 镜像。
2. 推送镜像到 GHCR镜像 tag 同时包含 commit SHA 和 `master`
3. SSH 到生产服务器,`git pull --ff-only origin master` 更新 Compose 和部署脚本。
4. 写入 `.env.production``APP_VERSION``APP_BUILD_TIME``WEB_IMAGE``SERVER_IMAGE`
5. 执行 `docker compose --env-file .env.production -f docker-compose.prod.yml pull web server` 拉取本次 SHA 镜像。
6. 启动数据库与 Redis执行 `pnpm --filter server db:deploy`
7. 执行 `docker compose --env-file .env.production -f docker-compose.prod.yml up -d --remove-orphans` 重启服务。
8. 运行发布 smoke test校验 `/api/v1/health/version`、前端首页、产品页、产品 API、V2.2 读路径和 AI 配置端点,并确认运行中的后端版本等于本次 commit SHA。
如果最后一步失败Actions 会红掉,说明“代码已合并”不等于“线上容器已更新”或关键读路径不可用。本地或服务器也可以手工运行:
```bash
pnpm deploy:check-runtime http://localhost/api/v1/health/version <expected-commit-sha>
pnpm deploy:smoke -- --base-url http://localhost --expected-version <expected-commit-sha>
```
## Nginx 路由
`deploy/nginx/default.conf.template` 使用官方 Nginx 镜像的模板机制生成配置:
- `/api/` 转发到 `server:3001`
- `/` 转发到 `web:3000`
- `X-Forwarded-Proto``X-Forwarded-For` 等反向代理头会透传给后端
生产 Compose 默认只监听 HTTP 80。HTTPS 建议优先交给云负载均衡、CDN 或宿主机外层证书管理工具;如果要让本 Compose 内的 Nginx 直接处理 HTTPS可以在后续增加证书 volume 和 443 server block。
## 监控与告警基线
V2.8 提供可选 `monitoring` profile不影响默认生产启动。启用前先在 `.env.production` 设置 `GRAFANA_ADMIN_PASSWORD`,不要使用示例密码对外暴露 Grafana。
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml --profile monitoring up -d
```
默认入口:
- Prometheus: `http://localhost:9090`
- Grafana: `http://localhost:3002`
配置目录在 `deploy/monitoring/`。基线覆盖:
- `FtbPostgresDown`PostgreSQL 不可用。
- `FtbDiskPressure`:宿主机根分区低于 15% 可用空间。
- `FtbSlowApiLogBurst`:服务端慢 API 日志在 10 分钟内超过阈值。
- `FtbSlowPrismaLogBurst`:慢 Prisma 查询日志在 10 分钟内超过阈值。
- `FtbJobFailureLogBurst`AppData 同步、AI 调用或后台任务失败日志出现。
- `FtbXiaobaoSummaryStale``xiaobao_risk_summaries` 存在 dirty 或超过 6 小时未更新的摘要。
Prometheus 只加载本地规则,不提交真实通知密钥。接入 Slack、企业微信、邮件等通知时把 Alertmanager receiver 放在未跟踪的服务器文件或环境变量中。
## 数据持久化
生产 Compose 使用三个命名 volume
- `postgres_data`PostgreSQL 数据库,包含业务主数据和 `app_data`
- `redis_data`Redis AOF 数据。
- `server_data`NestJS 写入的 AI Provider 配置文件,例如 `data/ai-config.json`
浏览器不再作为业务数据主存储。清浏览器缓存不会删除产品、项目、版本、任务、测试用例、Bug 等业务数据。
## 备份与恢复
备份分两类PostgreSQL 业务数据和 `server_data` volume 中的运行时配置。真实备份文件默认写到 `backups/`,该目录已加入 `.gitignore`,不要把 dump 或 tar 包提交到仓库。
先演练命令,不写文件:
```bash
pnpm backup:postgres -- --dry-run --env-file .env.production
pnpm backup:server-data -- --dry-run --env-file .env.production
```
执行正式备份:
```bash
pnpm backup:postgres -- --env-file .env.production
pnpm backup:server-data -- --env-file .env.production
```
PostgreSQL 备份使用 `pg_dump --format=custom --no-owner --no-acl`,便于跨环境恢复。`server_data` 备份使用只读 volume mount 和 `tar -czf`,覆盖 AI Provider 配置等后端运行时文件。
恢复数据库必须显式确认覆盖。默认命令会拒绝执行,防止误删现有库:
```bash
pnpm restore:postgres -- --env-file .env.production --input backups/postgres/ftb_pm-postgres-20260708T120000Z.dump
```
确认要把目标数据库重建为 fresh DB 后,再运行:
```bash
pnpm restore:postgres -- \
--env-file .env.production \
--input backups/postgres/ftb_pm-postgres-20260708T120000Z.dump \
--confirm-overwrite
```
恢复前建议先 dry-run 看清将执行的 `psql/dropdb/createdb/pg_restore` 步骤:
```bash
pnpm restore:postgres -- \
--dry-run \
--confirm-overwrite \
--env-file .env.production \
--input backups/postgres/ftb_pm-postgres-20260708T120000Z.dump
```
如果要恢复到临时库做校验,不覆盖当前生产库:
```bash
pnpm restore:postgres -- \
--env-file .env.production \
--input backups/postgres/ftb_pm-postgres-20260708T120000Z.dump \
--target-db ftb_pm_restore_check \
--confirm-overwrite
```
## 运维 Runbooks
生产发布、迁移和异常处置优先使用这些手册:
- `docs/runbooks/migration-rollback.md`:发布失败、迁移失败、数据恢复和镜像回滚。
- `docs/runbooks/appdata-retirement.md`AppData key 分阶段退场、双读核对、归档和回滚。
- `docs/runbooks/xiaobao-background-jobs.md`:小宝摘要 stale 告警、手动刷新和未来后台任务规则。
- `docs/production-readiness.md`:生产发布前后证据清单。
提交前运行 runbook 扫描:
```bash
pnpm docs:check-runbooks
```
## 升级流程
```bash
git pull
pnpm deploy:verify
docker compose --env-file .env.production -f docker-compose.prod.yml build
docker compose --env-file .env.production -f docker-compose.prod.yml up -d
docker compose --env-file .env.production -f docker-compose.prod.yml exec server pnpm --filter server db:deploy
```
升级前建议先备份数据库:
```bash
pnpm backup:postgres -- --env-file .env.production
pnpm backup:server-data -- --env-file .env.production
```
## 常见排查
后端是否启动:
```bash
curl http://localhost/api/v1/config/ai
```
数据库是否可用:
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml exec postgres pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"
```
查看日志:
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml logs -f server
docker compose --env-file .env.production -f docker-compose.prod.yml logs -f web
docker compose --env-file .env.production -f docker-compose.prod.yml logs -f nginx
```
如果前端能打开但数据为空,优先检查:
1. `NEXT_PUBLIC_API_URL` 是否为 `/api/v1` 或正确的完整 API 地址。
2. `curl http://localhost/api/v1/config/ai` 是否返回 200。
3. `server` 日志里是否有 Prisma 或 `DATABASE_URL` 错误。
4. 是否已执行 `pnpm --filter server db:deploy`