Files
zhuiguang-ai/.trae/specs/modules/09-devops.md
T

315 lines
10 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.
# 运维与部署模块
## 服务器与基础设施
### 环境信息
- **域名**: www.zhuig.com (HTTPS,SSL证书自动续期)
- **云服务器**: 119.45.242.239 (登录名: ubuntu, 密钥: `C:\SGP_KF\ZhuiGuangAI\zhuiguang-ai\Pem\zg.pem`)
- **数据库**: 阿里云RDS MySQL — rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306
- **Redis**: Docker容器 redis-cache:6379,有密码认证(共享服务)
- **Nacos**: Docker容器 nacos:8848(共享服务)
- **MinIO**: Docker容器 minio:9000(共享服务)
- **部署目录**: /home/ubuntu/zhuiguang-ai
- **访问地址**: https://www.zhuig.com (HTTP自动跳转HTTPS)
- **本地Git同步目录**: C:\gitbf
### 端口规范
- **应用端口范围**: 8301-8310(预留扩展)
- **默认端口**: 8301
- **强制要求**: 本项目端口必须锁定在8301-8310区间内,禁止使用其他端口
---
## 容器化部署架构
### 容器清单
| 容器名 | 镜像 | 端口 | 用途 |
|--------|------|------|------|
| `zhuiguang-ai-app` | `zhuiguang-ai:latest` | 8301 | Next.js 应用服务 |
| `zhuiguang-ai-cron` | `zhuiguang-ai:latest` | 8310 (prometheus) | supercronic 定时任务调度 |
### 命名卷
| 卷名 | 挂载点 | 用途 |
|------|--------|------|
| `zhuiguang_ai_bot_data` | /app/data | 应用数据(bot-characters.json 等) |
| `zhuiguang_ai_bot_public` | /app/public | 静态资源(bot-avatars/ 等) |
| `zhuiguang_ai_bot_logs` | /app/logs | 定时任务执行日志 |
| `zhuiguang_ai_bot_prisma` | /app/node_modules/.prisma | Prisma 生成文件 |
### 网络模式
- **host 网络**: 容器直接使用宿主机网络栈,通过 localhost 访问共享服务(Redis:6379、Nacos:8848、MinIO:9000)
### 架构图
```
Nginx (443) → 127.0.0.1:8301 → zhuiguang-ai-app (Docker, host 网络)
Cron → zhuiguang-ai-cron (Docker, supercronic, host 网络)
共享卷: data / public / logs / prisma (命名卷)
外部: 阿里云 RDS / 共享 Redis / 共享 Nacos / 共享 MinIO
```
---
## Nginx配置
- 文件: `/etc/nginx/sites-enabled/zhuiguang-ai`
- HTTPS反向代理到本地8301端口
- HTTP自动跳转HTTPS
- SSL证书自动续期
- **注意**: Nginx 始终代理 `127.0.0.1:8301`,切换 PM2→Docker 时无需改动
---
## 部署流程
### 本地开发
```bash
# 1. 安装依赖
npm install
# 2. 配置环境变量
# 编辑 .env 文件
# 3. 数据库迁移
npx prisma migrate dev
# 4. 启动开发服务器
npm run dev
```
### 生产构建 + 部署
```bash
# 1. 构建镜像
cd /home/ubuntu/zhuiguang-ai
docker build -t zhuiguang-ai:latest .
# 2. 停止旧容器
docker stop zhuiguang-ai-app zhuiguang-ai-cron
docker rm zhuiguang-ai-app zhuiguang-ai-cron
# 3. 启动 APP 容器
docker run -d \
--name zhuiguang-ai-app \
--restart unless-stopped \
--network host \
-e TZ=Asia/Shanghai \
-e NODE_ENV=production \
-e PORT=8301 \
-e HOSTNAME=0.0.0.0 \
-v /home/ubuntu/zhuiguang-ai/env/.env.production:/app/.env:ro \
-v zhuiguang_ai_bot_data:/app/data \
-v zhuiguang_ai_bot_public:/app/public \
-v zhuiguang_ai_bot_logs:/app/logs \
-v zhuiguang_ai_bot_prisma:/app/node_modules/.prisma \
zhuiguang-ai:latest
# 4. 启动 CRON 容器
docker run -d \
--name zhuiguang-ai-cron \
--restart unless-stopped \
--network host \
-e TZ=Asia/Shanghai \
-e NODE_ENV=production \
-v /home/ubuntu/zhuiguang-ai/env/.env.production:/app/.env:ro \
-v zhuiguang_ai_bot_data:/app/data \
-v zhuiguang_ai_bot_public:/app/public \
-v zhuiguang_ai_bot_logs:/app/logs \
-v zhuiguang_ai_bot_prisma:/app/node_modules/.prisma \
-v /home/ubuntu/zhuiguang-ai/crontab.txt:/app/crontab.txt:ro \
zhuiguang-ai:latest /usr/local/bin/entrypoint-cron.sh
# 5. 验证
docker ps --filter name=zhuiguang-ai
curl -I http://localhost:8301/
```
### 使用 docker-compose(推荐)
```bash
cd /home/ubuntu/zhuiguang-ai
docker-compose down
docker-compose build
docker-compose up -d
```
### 测试部署(端口 8302,与生产并行)
```bash
cd /home/ubuntu/zhuiguang-ai
docker-compose -f docker-compose.test.yml down
docker-compose -f docker-compose.test.yml build
docker-compose -f docker-compose.test.yml up -d
```
---
## Docker 镜像构建
### Dockerfile 结构
```
阶段 1: deps — npm ci 安装依赖(含 devDependencies)
阶段 2: builder — prisma generate + npm run build
阶段 3: runner — 仅复制生产依赖 + 构建产物,最终镜像 ~1.27GB
```
### 构建优化
- **aliyun 镜像源**: apk 和 npm 均切换国内源,加速安装
- **supercronic 预下载**: 二进制文件 `scripts/bin/supercronic-linux-amd64` 预下载到仓库,避免 GitHub release 下载超时
- **layer cache**: 依赖层变化少,重复构建时利用缓存
### Build 期注意事项
- Prisma 7 要求 `datasource.url` 在 `prisma.config.ts` 中,不能在 `schema.prisma` 中
- Next.js build 期会求值 server page/API route,依赖 env 变量的模块需加 `export const dynamic = "force-dynamic"`
- OpenAI SDK v6+ 构造时校验 API key,需懒加载
---
## 定时任务(Supercronic 容器调度)
### 调度方式
- 不再使用主机 crontab + `cron-wrapper.sh`
- 由 `zhuiguang-ai-cron` 容器内 supercronic 调度
- 配置文件: `crontab.txt`(项目根目录)
- 修改 crontab.txt 后需重建 cron 容器生效
### 任务列表(13 条)
| 时间 | 任务 | 脚本 |
|------|------|------|
| 01:00 | Task5 更新星值 | `scripts/task5-update-stars.mjs` |
| 02:00 | Bot 技能结晶 | `scripts/bot-skill-crystallize.mjs` |
| 03:00 | Task3 工具巡检 | `scripts/task3-check-tools.mjs` |
| 04:00 | Task6 评测热门 | `scripts/task6-review-hot.mjs` |
| 05:00 | Bot 亲和度与画像 | `scripts/bot-affinity-update.mjs` |
| 05:00 | Task4 发现技能 | `scripts/daily-discover.mjs` |
| 06:00 | Task1 发现工具 | `scripts/task1-discover-tools.mjs` |
| 07:30 | AI日报 | `scripts/daily-news.mjs` |
| 08:00 | Task7 新闻推社区 | `scripts/task7-news-to-community.mjs` |
| 09:00-23:00 | Bot 活动引擎 | `scripts/bot-activity.mjs`(每小时) |
| 21:30 | Bot 反馈闭环 | `scripts/bot-feedback-loop.mjs` |
| 周日 22:30 | Bot 跨板块亲和度 | `scripts/bot-affinity-update.mjs` |
| 周日 02:00 | Bot 周度复盘 | `scripts/bot-weekly-review.mjs` |
### 日志目录
- 容器内路径: `/app/logs/`(挂载到 Docker volume `zhuiguang_ai_bot_logs`)
- 查看日志: `docker logs zhuiguang-ai-cron` 或 `docker exec zhuiguang-ai-cron cat /app/logs/bot-activity.log`
---
## 容器运维命令
### 状态查看
```bash
# 容器状态
docker ps --filter name=zhuiguang-ai
# 容器健康状态
docker inspect zhuiguang-ai-app --format '{{.State.Health.Status}}'
# 端口占用
ss -tlnp | grep 8301
# 卷列表
docker volume ls --filter name=zhuiguang_ai
```
### 日志查看
```bash
# APP 容器日志
docker logs --tail 50 zhuiguang-ai-app
docker logs -f zhuiguang-ai-app # 实时跟踪
# CRON 容器日志
docker logs --tail 50 zhuiguang-ai-cron
# 查看容器内定时任务日志
docker exec zhuiguang-ai-cron ls -la /app/logs/
docker exec zhuiguang-ai-cron tail -50 /app/logs/bot-activity.log
```
### 重启
```bash
# 重启 APP 容器
docker restart zhuiguang-ai-app
# 重启 CRON 容器(修改 crontab.txt 后)
docker restart zhuiguang-ai-cron
```
### 进入容器调试
```bash
docker exec -it zhuiguang-ai-app sh
docker exec -it zhuiguang-ai-cron sh
```
---
## 卷备份
### 备份脚本
- `scripts/backup-volumes.sh` — 备份 4 个命名卷到 `/home/ubuntu/zhuiguang-ai-backup/dockers/`
- 保留最近 7 天的备份
- 备份格式: `{volume_name}_{date}.tar.gz`
### 主机备份 cron
- `scripts/install-cron-backup.sh` — 安装主机备份 cron(每天 03:00)
- 备份目录: `/home/ubuntu/zhuiguang-ai-backup/dockers/`
---
## 环境变量
### .env.production 配置
```bash
# 数据库(必填)
DATABASE_URL="mysql://mohe001:***@rm-0jlbgr2rv6dj3t6jngo.mysql.rds.aliyuncs.com:3306/zhuiguang_ai?charset=utf8mb4"
# NextAuth(必填)
NEXTAUTH_URL="http://localhost:8301"
NEXTAUTH_SECRET="请生成一个随机高强度密钥(至少32位)"
# GitHub API(必填,提升限流60→5000次/小时)
GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"
# DeepSeek API(必填)
DEEPSEEK_API_KEY="sk-..."
DEEPSEEK_MODEL="deepseek-v4-pro"
# OpenAI API(Bot 活动引擎使用)
OPENAI_API_KEY="sk-..."
```
> **注意**: 容器运行时 `.env` 文件以只读方式挂载(`:ro`),避免容器内误修改。
---
## 安全配置
### HTTP 响应头
next.config.mjs 配置以下安全响应头:
- **CSP (Content-Security-Policy)**: `default-src 'self'` + 安全白名单
- **HSTS (Strict-Transport-Security)**: `max-age=31536000; includeSubDomains`
- **Permissions-Policy**: `camera=(), microphone=(), geolocation=()`
- **X-Content-Type-Options**: `nosniff`
- **X-Frame-Options**: `DENY`
- **X-XSS-Protection**: `1; mode=block`
- **Referrer-Policy**: `strict-origin-when-cross-origin`
### 权限控制
- middleware.ts 中 `/admin/*` 和 `/api/admin/*` **仅 admin 角色可访问**(VIP 用户无权限)
---
## 踩坑记录
- Next.js 14不支持useActionState,登录页用原生表单POST
- Prisma MariaDB adapter需要连接字符串方式初始化
- 图片域名需在next.config.mjs中配置remotePatterns
- 热重载后需清除.next缓存: 删除.next目录后重启
- Chart.js组件需用dynamic import + ssr: false,不支持服务端渲染
- Prisma 7.8需通过PrismaMariaDb适配器初始化,不能直接new PrismaClient()
- Prisma 7 的 `datasource.url` 必须放在 `prisma.config.ts` 中,不能在 `schema.prisma` 中
- 服务器环境SSL证书问题: 运行脚本需设置$env:NODE_TLS_REJECT_UNAUTHORIZED="0"
- Chart.js font.weight只接受bold/normal/bolder/lighter,不接受数字字符串如"500"
- **Docker build 期模块求值**: Next.js build 时会预渲染 server page 和 API route,导致 Prisma/OpenAI 等模块被求值。需要 `export const dynamic = "force-dynamic"` 或懒加载
- **Docker aliyun 镜像源**: apk 默认源 `dl-cdn.alpinelinux.org` 极慢(1m23s),切换 `mirrors.aliyun.com` 仅需 0.134s;npm 切换 `registry.npmmirror.com`
- **Supercronic 下载**: GitHub release 的 `release-assets.githubusercontent.com` 在服务器上可能超时,建议预下载二进制到仓库
- **Docker host 网络**: 使用 host 网络模式才能让容器内进程通过 localhost 访问共享服务(Redis、Nacos、MinIO)