Files
sbnews/docs/superpowers/specs/2026-08-02-production-docker-compose-design.md
T

232 lines
8.1 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.
# Sport Era 生产 Docker Compose 设计
## 1. 目标
在生产服务器 `/www/wwwroot/sbnews` 中固定使用 `dev.1.0.0` 分支,通过一份统一的生产 Compose 编排运行 Sport Era 的 API、定时任务、爬虫、AI 知识库 Worker、管理后台和 uni-app H5。
生产环境继续使用宿主机 MySQL、Redis 和宝塔 Nginx。Compose 不管理数据库数据,也不占用宿主机的 80、443 端口。
## 2. 域名与入口
宝塔 Nginx 负责域名、HTTPS 证书和公网入口,并反向代理到仅在宿主机回环地址监听的容器服务:
| 域名 | 服务 | 反向代理目标 |
| --- | --- | --- |
| `api.sbnews.net` | ThinkPHP API | `http://127.0.0.1:8000` |
| `keislwo.sbnews.net` | Admin SPA | `http://127.0.0.1:5176` |
| `web.sbnews.net` | uni-app H5 SPA | `http://127.0.0.1:5177` |
容器不直接处理公网 TLS,也不直接暴露 80、443、9000 等内部服务端口。
## 3. Compose 服务
新增 `docker/docker-compose.prod.yml`Compose 项目名为 `sport-era-prod`
### 3.1 Server
- 使用项目 PHP 8.0 FPM 镜像及 OPcache。
- 挂载 `/www/wwwroot/sbnews/server``/likeadmin_php/server`
- 挂载私有 PHP 生产环境文件为 `/likeadmin_php/server/.env`
- 使用 host 网络访问宿主机 MySQL 和 Redis。
- PHP-FPM 仅监听 `127.0.0.1:9000`
- 使用 `restart: unless-stopped` 和有限大小的 Docker 日志。
### 3.2 API Nginx
- 使用 host 网络,通过 `127.0.0.1:9000` 访问 PHP-FPM。
- 仅监听 `127.0.0.1:8000`
- 根目录为 `/likeadmin_php/server/public`
- 支持 ThinkPHP 路由重写、上传大小限制、静态资源缓存和代理来源信息。
- 挂载生产 Nginx 日志目录。
### 3.3 Scheduler
- 与 Server 使用同一 PHP 镜像、源码和私有环境文件。
- 使用 host 网络。
- 独立循环执行 `php think crontab`,间隔 60 秒。
- 不承载 HTTP 请求。
### 3.4 Crawler
- 复用 `docker/crawler/Dockerfile` 构建的镜像。
- 使用 host 网络连接宿主机 MySQL、Redis。
- 复用现有 `crawler_tasks.yaml` 生成容器 cron。
- 持久化 `docker/crawler/logs``docker/crawler/data`
### 3.5 KB Worker
- 与 Crawler 复用同一镜像。
- 使用 host 网络连接 MySQL、Redis。
- 持续消费 Redis Stream `ai:kb:sync:stream`
- 对文章、帖子、彩票和比赛内容生成知识库文档、切片及 Embedding。
- 保留现有批量大小、阻塞时间和重试参数。
### 3.6 Admin
- 使用 Node 20 多阶段构建。
- 构建阶段安装锁定依赖并生成 Vite 生产资源。
- `VITE_APP_BASE_URL` 固定传入 `https://api.sbnews.net`
- 运行阶段只保留静态 Nginx 和构建产物。
- Nginx 仅监听 `127.0.0.1:5176`,并配置 SPA 路由回退。
### 3.7 uni-app H5
- 使用 Node 20 多阶段构建。
- 构建阶段执行 H5 生产构建。
- `VITE_APP_BASE_URL` 固定传入 `https://api.sbnews.net`
- 修改用户端配置,使生产 API 地址来自构建环境变量,不继续固定指向测试域名。
- 运行阶段只保留静态 Nginx 和 H5 构建产物。
- Nginx 仅监听 `127.0.0.1:5177`,并配置 SPA 路由回退。
PC 前台不包含在本次生产 Compose 范围内。
## 4. 网络设计
所有需要访问宿主机 MySQL、Redis 或回环端口的服务采用 host 网络:
- MySQL`127.0.0.1:3300`
- Redis`127.0.0.1:6377`,数据库编号 2
- PHP-FPM`127.0.0.1:9000`
- API Nginx`127.0.0.1:8000`
- Admin Nginx`127.0.0.1:5176`
- H5 Nginx`127.0.0.1:5177`
host 网络避免修改宿主机数据库监听地址和账号授权范围。各 HTTP/FastCGI 端口必须显式绑定回环地址,防止绕过宝塔直接访问。
## 5. 配置与密钥
生产环境使用两份互不混用的私有配置:
### 5.1 PHP 配置
文件:`docker/.env.server.production`
- 使用 ThinkPHP INI 风格配置。
- 包含数据库、Redis 以及 Server 运行所需的其他私有参数。
- 只存在于生产服务器,权限设置为 `600`
- 挂载到 Server 和 Scheduler 的项目 `.env`
### 5.2 Crawler 配置
文件:`docker/.env.crawler.production`
- 使用 dotenv 格式。
- 包含 `DQD_DB_*``DQD_REDIS_*`、Embedding 及爬虫所需私有参数。
- 由 Crawler 与 KB Worker 共用。
- 只存在于生产服务器,权限设置为 `600`
Git 只提交对应的 `.example` 文件,所有密码使用占位符。`.gitignore` 必须忽略真实生产配置。
`server/config/cache.php` 中现存的非空 Redis 默认密码需要清空;各环境必须通过私有 `.env` 显式提供密码。已经公开或进入源码历史的生产密码应在部署完成后轮换。
## 6. 持久化与日志
| 数据 | 宿主机位置 |
| --- | --- |
| Server 源码、上传和运行目录 | `/www/wwwroot/sbnews/server` |
| Crawler 日志 | `/www/wwwroot/sbnews/docker/crawler/logs` |
| Crawler 锁与运行数据 | `/www/wwwroot/sbnews/docker/crawler/data` |
| API Nginx 日志 | `/www/wwwroot/sbnews/docker/log/nginx/prod-logs` |
| MySQL 数据 | 由宿主机/宝塔管理 |
| Redis 数据 | 由宿主机/宝塔管理 |
所有 Compose 服务使用有限大小、有限文件数量的 Docker JSON 日志配置,防止日志无限增长。
## 7. 发布流程
生产目录固定跟踪 `dev.1.0.0`
```bash
cd /www/wwwroot/sbnews
git switch dev.1.0.0
git pull --ff-only origin dev.1.0.0
sudo docker compose -f docker/docker-compose.prod.yml config -q
sudo docker compose -f docker/docker-compose.prod.yml up -d --build
```
Admin 和 H5 每次部署都从当前提交重新构建。Server 继续挂载当前生产目录源码,更新代码后由新容器或现有挂载立即读取;执行统一 `up -d --build` 保证运行镜像和配置同步。
Compose 不自动执行数据库迁移、SQL 导入或破坏性数据操作。
## 8. 健康检查与验收
Compose 为 API、Admin 和 H5 配置健康检查。部署后至少执行:
```bash
sudo docker compose -f docker/docker-compose.prod.yml ps
curl -f http://127.0.0.1:8000/api/index/config
curl -I http://127.0.0.1:5176/
curl -I http://127.0.0.1:5177/
```
再通过公网域名检查宝塔反向代理和 HTTPS:
```bash
curl -I https://api.sbnews.net/api/index/config
curl -I https://keislwo.sbnews.net/
curl -I https://web.sbnews.net/
```
同时检查:
- Server、Scheduler、Crawler、KB Worker 均持续运行。
- Scheduler 能产生正常定时任务日志。
- Crawler 的容器 cron 已正确生成。
- KB Worker 已连接 Redis Stream,且没有持续重试错误。
- Admin/H5 刷新子路由不会返回 404。
- Git 跟踪文件中不存在真实数据库、Redis 或 AI 密钥。
## 9. 回滚
回滚前必须确认生产工作区没有人工修改:
```bash
git status --short
```
切换到已知正常提交并重新构建:
```bash
git switch --detach <正常提交ID>
sudo docker compose -f docker/docker-compose.prod.yml up -d --build
```
恢复跟踪生产分支:
```bash
git switch dev.1.0.0
```
构建失败时不主动删除旧容器或旧镜像,避免构建失败直接中断当前线上服务。
## 10. 实施文件范围
新增文件:
- `docker/docker-compose.prod.yml`
- `docker/Dockerfile.admin`
- `docker/Dockerfile.uniapp-h5`
- `docker/config/nginx/conf.d/sport-era.prod-api.conf`
- `docker/config/nginx/static/admin.conf`
- `docker/config/nginx/static/uniapp-h5.conf`
- `docker/config/php/conf.d/zz-opcache.prod.ini`
- `docker/config/php/php-fpm.prod.conf`
- `docker/.env.server.production.example`
- `docker/.env.crawler.production.example`
- `admin/.dockerignore`
- `uniapp/.dockerignore`
- `docs/生产环境Docker部署说明.md`
修改文件:
- `.gitignore`
- `uniapp/src/config/index.ts`
- `server/config/cache.php`
- `docs/业务进度管理.md`
## 11. 实施验证边界
本地实施阶段执行静态 Compose 展开和配置检查,不自动执行完整 Admin/H5 构建,也不直接操作生产服务器。所有真实生产密钥由服务器管理员写入私有环境文件。
源码或运行配置修改完成后创建独立 Git 提交,不包含当前工作区中既有的社区页面或其他无关改动。由于会修改 `server/config/cache.php`,提交后按项目规范同步测试服;生产环境由服务器在 `/www/wwwroot/sbnews` 拉取并部署。