website-scripts/deploy-ai-readme.md

154 lines
5.9 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.

# deploy-ai.sh — tlyq.ai 站点部署脚本
## 概述
`deploy-ai.sh` 将本地代码部署到 tlyq.ai 云服务器txjpIP: 43.133.38.210)。采用"源码上传 → 服务器构建"模式,本地不做生产构建。
**核心流程**:打包源码 → 上传至 txjp → 服务器 `npm install` + `npm run build` → 容器重启生效
## 用法
```bash
bash scripts/deploy-ai.sh [选项]
```
| 选项 | 说明 |
|------|------|
| 无参数 | 自动检测:初次构建 or 增量更新(源码快照比对) |
| `--force` | 强制完整构建(跳过快照比对) |
| `--restart` | 仅重启容器(跳过构建) |
| `--init` | 强制初次完整构建 |
## 站点选择
脚本启动后显示交互式菜单:
| 编号 | 站点 | 容器 | 构建方式 |
|------|------|------|---------|
| 1 | www.tlyq.ai | — | Next.js `output: 'export'` 静态站点 |
| 2 | cloud.tlyq.ai | — | 纯静态 HTML |
| 3 | token.tlyq.ai | — | 纯静态 HTML |
| 4 | issue.tlyq.ai | issue-ai | Next.js standaloneDocker |
| 5 | assets.tlyq.ai | assets-ai | Next.js standaloneDocker |
| 6 | oa.tlyq.ai | oa-ai | Next.js standaloneDocker |
## 部署流程
### 通用步骤
1. **链接替换**`localhost` → 正式域名www/cloud/token 站点OA 站点额外替换内部 API 地址)
2. **快照比对**:计算本地源码 MD5与服务器上次快照对比无变化则跳过构建
3. **打包上传**tar 打包(排除 `node_modules`、`.next`、`.env` 等scp 上传至 txjp
4. **解压同步**rsync 同步源码到目标目录
5. **依赖安装**:服务器 `npm install --prefer-offline`
6. **环境变量**:写入生产环境所需的环境变量到 `.env`
7. **构建**:服务器 `npm run build`
8. **清理**:删除 Alpine musl 残留sharp、swc
9. **重启容器**`docker compose up -d` + `docker compose restart`
10. **快照保存**:保存本次源码 MD5 用于下次比对
### issue-ai 专属
- 构建前写入 `ASSETS_API_URL=http://assets-ai:3000/api`
- 构建前写入 `NEXT_PUBLIC_ASSETS_URL=https://assets.tlyq.ai`
- **部署后自动验证 issue→assets API 连通性**(见下方)
### assets-ai 专属
- 构建前写入 `NEXT_PUBLIC_ISSUE_URL=https://issue.tlyq.ai/tickets`
- 构建前写入 `ISSUE_API_URL=http://issue-ai:3000/api`
### OA 专属
- 替换三类 URL前端导航卡片`localhost` → 生产域名)、服务端内部 API`localhost` → 容器名)、退出登录重定向
## 部署后验证
### 部署后 API 连通性检查
部署 issue-ai 和 assets-ai 后自动执行双向连通性检查,均带 **重试机制**3 次、间隔 10s应对同时部署两个站点时目标容器暂不可达的情况。
| 部署站点 | 检查方向 | 使用 Key | 目标 URL |
|---------|---------|---------|----------|
| issue-ai | issue → assets | `ASSETS_API_KEY` | `ASSETS_API_URL/assets?pageSize=1` |
| assets-ai | assets → issue | `ISSUE_API_KEY` | `ISSUE_API_URL/tickets?pageSize=1` |
流程:
1. 将连通性检查脚本发送到 txjp 宿主机
2. `docker cp` 到对应容器内
3. 容器内 Node.js 发起 HTTP 请求,失败自动重试(最多 3 次,间隔 10s
4. 返回 200 → 通过;全部重试仍失败 → **部署失败退出**
**错误输出示例**
```
[✗] issue→assets API 连通性检查失败!请检查 ASSETS_API_KEY 是否在 assets-ai 中注册
连接失败: HTTP 401 (第1次)
10s 后重试...
连通失败: HTTP 401 (第2次)
已达最大重试次数
```
## 排除文件
打包时排除以下目录和文件,不上传到服务器:
| 类别 | 排除项 |
|------|--------|
| 依赖 | `node_modules` |
| 构建产物 | `.next`、`out`、`data` |
| 环境配置 | `.env`、`.env.local`、`.env.development`、`.env.production` |
| 版本控制 | `.git` |
| 文档 | `docs` |
| 报告 | `reports/*.docx` |
| macOS | `._*` |
部署后服务器上的 `.env.local` / `.env.development` / `.env.production` 会被自动删除,防止覆盖 `.env` 中的生产配置。
## 源码快照机制
脚本计算本地源码文件的组合 MD5保存到服务器的 `/tmp/.snapshot.{site}.md5`。下次部署时比对,若无变化则跳过构建仅重启容器。`--force` 可绕过此机制。
快照包含:所有源码文件(排除 `node_modules`、`.next`、`out`、`data`、`reports`、`docs`、`.env*`、`.git`)。
## 故障排查
### 构建失败
```bash
# 查看服务器构建日志
ssh txjp "tail -100 /tmp/build_output.txt"
```
### 容器启动失败
```bash
ssh txjp "docker logs {container}"
```
### 连通性检查失败
```bash
# 手动验证 issue→assets 连通性
ssh txjp "docker exec issue-ai sh -c 'cd /app && NODE_PATH=/app/node_modules node -e \"
const http = require(\\\"http\\\");
const url = process.env.ASSETS_API_URL + \\\"/assets?pageSize=1\\\";
const key = process.env.ASSETS_API_KEY || \\\"\\\";
http.get(url, {headers:{\\\"Authorization\\\":\\\"Bearer \\\"+key}}, (res) => {
console.log(\\\"status:\\\", res.statusCode);
process.exit(res.statusCode === 200 ? 0 : 1);
}).on(\\\"error\\\", (e) => { console.error(e.message); process.exit(1); });
\"'"
# 确认 assets-ai 的 api_keys 表中是否有对应的 key
ssh txjp "docker exec assets-ai node -e \"
const db = require('better-sqlite3')('/app/data/assets.db');
const rows = db.prepare('SELECT id, name, is_active FROM api_keys').all();
rows.forEach(r => console.log(JSON.stringify(r)));
\""
```
## 注意事项
- **跨容器凭据**:禁止在代码或配置中硬编码另一服务的密码,通过运行时读取源容器环境变量获取
- **共享 JWT 密钥**:所有 `.tlyq.ai` 子站点的 `JWT_SECRET``COOKIE_DOMAIN` 必须一致
- **日期时区**:系统统一 UTC+8禁止使用 `toISOString()``datetime('now')`
- **nginx 重载**:容器重启后需 `docker restart nginx-ai` 清除 DNS 缓存
- **新增 npm 依赖**:需重建 Docker 镜像(`docker compose build --no-cache`),因为容器内 `/app/node_modules/` 来自镜像构建时