Files
koc-loop/docs/KOC LOOP 私有化部署指南.md
2026-08-15 03:57:50 +08:00

209 lines
9.2 KiB
Markdown
Raw Permalink 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.
# KOC LOOP 私有化部署指南
本文适用于 `main` 分支。目标架构是运维提出的Nginx 代理 + KOC 服务 + MySQL 数据库,并让后台、外部 KOC 领取页和 Agent MCP 都能通过一个公网域名访问。
## 1. 部署形态
| 组件 | 容器 | 作用 | 持久化 |
| --- | --- | --- | --- |
| Nginx | `nginx` | 公网入口、反向代理、托管 KOC 领取页 | 配置随镜像 |
| KOC 服务 | `app` | Next.js 后台、API、MCP、每天 09:00 自动采集 | 上传目录挂载卷 |
| MySQL 8 | `mysql` | 任务、笔记、领取、回填、账号、采集和用户数据 | MySQL 数据卷 |
访问路径:
- `https://你的域名/`:运营后台;
- `https://你的域名/koc/`:外部 KOC 领取和回填;
- `https://你的域名/api/mcp`Agent MCP
- `https://你的域名/api/health`:服务健康检查。
第一版按单实例 KOC 服务设计。MySQL 和上传目录均持久化。以后需要横向扩容时,可以把上传卷换成共享 NAS对象存储接口已与业务代码分离。
## 2. 服务器要求
- Linux 服务器一台,建议至少 4 核、8 GB 内存、100 GB 数据盘;
- Docker Engine 24+
- Docker Compose v2
- 可解析到服务器或负载均衡的公网域名;
- HTTPS 证书由公司网关、负载均衡或 Nginx 统一终止;
- 服务器可以访问飞书 OpenAPI 和正式数据采集 MCP。
服务器只需对公网开放 80/443。MySQL 不映射公网端口。
## 3. 准备代码与环境变量
```bash
git clone ssh://git@gta.gbotai.cn:42001/wufengping/koc-loop.git
cd koc-loop
git checkout main
cp .env.self-hosted.example .env.self-hosted
```
编辑 `.env.self-hosted`。必须替换所有 `replace-with-*` 占位值:
| 变量 | 用途 |
| --- | --- |
| `MYSQL_ROOT_PASSWORD` | MySQL root 密码,仅数据库容器使用 |
| `MYSQL_PASSWORD` | KOC 服务的数据库密码 |
| `APP_ORIGIN` | 后台公网地址,如 `https://koc.example.com` |
| `KOC_PORTAL_URL` | 领取页完整地址,如 `https://koc.example.com/koc/` |
| `SUPER_ADMIN_USERNAME` | 首次启动创建唯一超级管理员 |
| `SUPER_ADMIN_PASSWORD` | 首次启动的超级管理员初始密码,至少 8 位 |
| `ADMIN_INTERNAL_TOKEN` | 内部管理调用密钥 |
| `KOC_MCP_API_KEY` | Agent 调用 KOC LOOP MCP 的独立 Bearer 密钥 |
| `FEISHU_APP_ID` / `FEISHU_APP_SECRET` | 读取飞书内容表和配图 |
| `AI_TOOL_CENTER_MCP_URL` / `AI_TOOL_CENTER_MCP_KEY` | 小红书公开数据采集服务 |
| `ENABLE_SCHEDULER` | 是否启用每天 09:00 自动采集,生产保持 `true` |
密钥必须由密码管理器生成,禁止提交到 Git、聊天、部署日志或 URL。三个业务密钥 `ADMIN_INTERNAL_TOKEN``KOC_MCP_API_KEY``AI_TOOL_CENTER_MCP_KEY` 不得复用。
`APP_ORIGIN` 必须填写用户实际访问的 HTTPS 公网地址,不能填写 `localhost``app:3000` 或其他容器内部地址。Excel 中的视频下载链接会优先使用这个地址;前置网关还必须把原始 `Host``X-Forwarded-Host``X-Forwarded-Proto` 传给仓库内的 Nginx。
## 4. 首次启动
```bash
docker compose --env-file .env.self-hosted \
-f docker-compose.self-hosted.yml up -d --build
```
应用容器启动时会先执行同一套数据库迁移脚本,成功后才启动 KOC 服务。查看状态:
```bash
docker compose --env-file .env.self-hosted \
-f docker-compose.self-hosted.yml ps
curl -fsS http://127.0.0.1:${HTTP_PORT:-80}/api/health
```
健康检查应返回 `status: ok``database: true`
首次打开后台登录页时,系统会根据环境变量创建唯一超级管理员。创建成功后,可从运行环境移除 `SUPER_ADMIN_PASSWORD` 的明文值并重启应用;后续账号与密码统一在“用户管理”中维护。
## 5. Nginx 与 HTTPS
仓库内 `deploy/nginx/koc-loop.conf` 默认监听容器 80 端口,适合前置公司网关或负载均衡终止 HTTPS。
如果证书直接挂在本机 Nginx
1. 把证书和私钥以只读卷挂载进 `nginx` 容器;
2. 增加 443 `listen ... ssl` 配置;
3. 80 端口只做 301 跳转;
4. 保留 `/koc/` 静态规则、`/api/mcp` 长连接规则和 `/` 反向代理规则。
MCP 路由已经关闭代理缓冲并将超时时间延长到 1 小时,避免 Agent 的长调用被 Nginx 提前截断。仓库内 Nginx 同时将上传限制设为 85 MB用于接收最多 80 MB 的批量回填 Excel公司网关或负载均衡的请求体限制也必须不低于 85 MB。
视频下载接口必须经过 `/api/partner-image` 反向代理,正常响应应包含 `Content-Type: video/mp4` 和带 `.mp4` 文件名的 `Content-Disposition: attachment`。不要在网关层改写该响应类型或移除附件响应头。
## 6. 迁移原 Sites 数据
迁移分为数据库与图片两部分。先在原生产站点保持只读窗口,完成导出后再切换域名,避免新旧系统同时写入。
### 6.1 D1 数据导入 MySQL
把 D1 各表导出成一个 JSON 文件,结构如下:
```json
{
"tables": {
"partners": [{ "id": "...", "name": "..." }],
"tasks": [{ "id": "...", "name": "..." }],
"contents": [],
"accounts": [],
"claims": [],
"delegation_bundles": [],
"distributions": [],
"collection_runs": [],
"users": [],
"auth_sessions": [],
"mcp_export_tokens": []
}
}
```
先确保 MySQL 迁移已完成,再在应用环境中运行:
```bash
npm run db:import-json -- /backup/koc-d1-export.json
```
导入脚本按业务依赖顺序写入,并使用主键/唯一键安全更新已有记录。正式迁移前先在测试库演练并核对任务数、笔记数、领取数、发布数和账号数。
### 6.2 R2 媒体文件导入
把 R2 按原对象 key 导出到一个目录,目录层级必须保留,例如:
```text
content-assets/...
content-videos/...
publish-evidence/...
creator-center/...
```
运行:
```bash
UPLOAD_DIR=/data/koc/uploads \
npm run storage:import -- /backup/koc-r2-export
```
脚本会复制文件,并为缺少元数据的媒体文件生成 Content-Type 元数据。容器部署时也可以在宿主机临时挂载 `upload_data` 卷后执行。
## 7. 上线验收
必须逐项验证:
1. 超级管理员可以登录,普通用户看不到 KOC 资源模块;
2. 用真实飞书表格创建一个 1 篇测试任务;
3. 返回的领取链接以 `/koc/?task=` 开头;
4. 手机公网打开领取页,能查看正文与配图;
5. 回填短链/长链、上传发布截图、刷新后记录仍在;
6. 上传创作者截图并填写曝光量、阅读量;
7. 后台立即采集一篇笔记成功;
8. 保存次日采集计划,确认数据库产生 `collection_runs`
9. 图文任务导出的 Excel 内能直接看到原图和截图;
10. 视频任务导出的 Excel 不含“图片”列,包含“视频”列,点击链接能下载扩展名为 `.mp4` 且可正常播放的文件;
11. 批量回填 Excel 可以上传,发布链接、笔记截图和单篇笔记数据分析截图均能正确回写;
12. Agent 用 `KOC_MCP_API_KEY` 调用 `/api/mcp` 能发现全部工具;
13. 重启全部容器后数据、图片和视频不丢失。
## 8. 备份与恢复
每天至少备份:
- MySQL`mysqldump --single-transaction`
- `mysql_data` 卷;
- `upload_data` 卷;
- 当前 Git 提交号和脱敏后的环境变量清单。
备份必须复制到另一台机器或对象存储,不能只保存在部署服务器。恢复演练至少每季度一次。
## 9. 升级与回滚
升级前先备份数据库和上传卷:
```bash
git pull
docker compose --env-file .env.self-hosted \
-f docker-compose.self-hosted.yml up -d --build
```
应用容器每次启动都会按文件名顺序执行尚未应用的 `mysql/*.sql`。本次版本包含平台/视频字段、账号性别/简介/标签以及“当前联系人”字段的增量迁移;升级后应检查容器日志确认 `0005``0006``0007` 已执行或已被识别为历史迁移。
数据库迁移只允许向前追加新的 `mysql/*.sql` 文件,禁止修改已经在生产执行过的迁移。应用回滚到旧镜像前,要确认旧代码兼容当前数据库结构;涉及不可逆结构变化时,必须同时准备数据库恢复方案。
## 10. 运维排查
| 现象 | 处理 |
| --- | --- |
| `/api/health` 返回 503 | 查看 MySQL 容器健康状态与应用数据库变量 |
| 登录页可开但登录失败 | 确认迁移完成、超级管理员变量仅用于初始化 |
| 配图或截图 404 | 检查 `upload_data` 卷和 `UPLOAD_DIR=/data/koc/uploads` |
| Excel 视频链接出现 localhost 或无法访问 | 检查 `APP_ORIGIN`、公网域名和网关转发的 Host/Proto 请求头 |
| 视频下载后不是 MP4 或无法播放 | 检查 `/api/partner-image` 是否经过应用代理、文件是否完整,以及网关是否保留 Content-Type/Content-Disposition |
| 批量回填表上传返回 413 | 将公司网关、负载均衡和 Nginx 的请求体限制统一提高到至少 85 MB |
| 09:00 未自动采集 | 检查 `ENABLE_SCHEDULER=true`、服务器日志和采集 MCP 网络 |
| MCP 401 | 检查请求头是否为 `Authorization: Bearer <KOC_MCP_API_KEY>` |
| 飞书读取失败 | 检查应用权限、文档授权和服务器到飞书 OpenAPI 的网络 |
生产日志不得打印数据库密码、飞书 Secret、MCP key 或完整带 key 的采集服务 URL。