5.9 KiB
5.9 KiB
deploy-ai.sh — tlyq.ai 站点部署脚本
概述
deploy-ai.sh 将本地代码部署到 tlyq.ai 云服务器(txjp,IP: 43.133.38.210)。采用"源码上传 → 服务器构建"模式,本地不做生产构建。
核心流程:打包源码 → 上传至 txjp → 服务器 npm install + npm run build → 容器重启生效
用法
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 standalone(Docker) |
| 5 | assets.tlyq.ai | assets-ai | Next.js standalone(Docker) |
| 6 | oa.tlyq.ai | oa-ai | Next.js standalone(Docker) |
部署流程
通用步骤
- 链接替换:
localhost→ 正式域名(www/cloud/token 站点;OA 站点额外替换内部 API 地址) - 快照比对:计算本地源码 MD5,与服务器上次快照对比,无变化则跳过构建
- 打包上传:tar 打包(排除
node_modules、.next、.env等),scp 上传至 txjp - 解压同步:rsync 同步源码到目标目录
- 依赖安装:服务器
npm install --prefer-offline - 环境变量:写入生产环境所需的环境变量到
.env - 构建:服务器
npm run build - 清理:删除 Alpine musl 残留(sharp、swc)
- 重启容器:
docker compose up -d+docker compose restart - 快照保存:保存本次源码 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 |
流程:
- 将连通性检查脚本发送到 txjp 宿主机
docker cp到对应容器内- 容器内 Node.js 发起 HTTP 请求,失败自动重试(最多 3 次,间隔 10s)
- 返回 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)。
故障排查
构建失败
# 查看服务器构建日志
ssh txjp "tail -100 /tmp/build_output.txt"
容器启动失败
ssh txjp "docker logs {container}"
连通性检查失败
# 手动验证 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/来自镜像构建时