ops: 生产从 NAS 整体迁移到甲骨文云主机
NAS 局域网 IP 因重启被 DHCP 换过两次,磁盘/网络稳定性都不如已经跑着好几个 生产服务的甲骨文机器。整体搬迁:应用 + 数据库都搬走,NAS 只保留 Gitea(这个 仓库的源码托管,未动)。 ## 迁移过程(已核对无损) - MariaDB:NAS 导出(10.11 源库,处理了只有新版本才有的 `/*M!999999` 注释) → 导入甲骨文 MariaDB 10.3.39,**20 张表逐条精确 COUNT(*) 比对完全一致** - 冻结 NAS(停服务)后又 dump 一次核对,确认期间零数据差异,才继续删库 - NAS `garmin_health_lab` 已 DROP DATABASE,备份在本地 `~/Desktop/Work/backups/garmin_health_lab_nas_backup_20260912.sql.gz` - 应用部署到 `/opt/garmin-health-lab`,systemd 单元(`ubuntu` 用户,非 root),和这台机器上的 ai-gateway/auth-hub 同一套约定 - 公网:`https://garmin.zichuan.xyz`,DNS + Caddy 反代 + 自动 TLS,替代原来 `NAS frpc → 甲骨文:8124` 那条隧道(已从 NAS 的 frpc.toml 精确删除对应段, 其它转发未动,改完逐条复检过没打断) - auth-hub 回调地址换成新域名,NAS/旧端口那几条历史回调已清掉 - AI 网关配置改本地回环(网关现在同机了),触发真实生成验证过 ## 一个当场拦下来的风险 甲骨文部署完默认开着自动同步。迁移窗口期两边并行跑时,若两边的调度器同时去 刷新 Garmin 令牌,会撞上按账号计算的 SSO 限流(`GarminHealthLab` 仓库 2026-09-03 那次事故的根因,那次修复花了一整天)。确认账号级 auto_sync 设置 本来是关的、这次算侥幸没撞上——不是设计上的保险,所以迁移期间显式在甲骨文这边 加了 `AUTO_SYNC=false`,直接在运行进程里验证过生效,确认 NAS 已冻结、数据无 缺口后才打开。 ## 文档 / 脚本同步 CLAUDE.md 明确写过"部署位置会变,排障前先查、不要凭记忆"——这次是第二次踩中 同一类问题(上次是"NAS 有没有生产环境"判断错),所以把 CLAUDE.md / PROGRESS.md / README.md / docs/* 里的部署事实全部更新,NAS 时代的 `deploy/` 脚本加废弃 说明保留参考、不删除,新增 `deploy/push_oracle.sh`(当场跑通一次真实部署)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
57
CLAUDE.md
57
CLAUDE.md
@@ -16,8 +16,8 @@
|
||||
**Framework7 9**(`framework7-react`,iOS 主题)+ Recharts 图表。根目录
|
||||
`package.json` 是 npm workspaces(含 `client`)。
|
||||
- **数据库**:可插拔数据层(`backend/db.py`),`DB_TYPE` 切换——
|
||||
本地开发 SQLite(`backend/data/health.db`,默认);生产 NAS MariaDB
|
||||
(`garmin_health_lab` 库,连接配置见 NAS 上 `backend/.env`)。
|
||||
本地开发 SQLite(`backend/data/health.db`,默认);生产 MariaDB(甲骨文云主机
|
||||
本机,`garmin_health_lab` 库,连接配置见该机 `/opt/garmin-health-lab/backend/.env`)。
|
||||
- **认证**:**auth-hub SSO**(OAuth2/OIDC,`services/auth_hub_client.py`),
|
||||
本地邮箱密码注册/登录已移除;应用内 JWT 由后端签发。
|
||||
- **AI**:自建 ai-gateway(OpenAI 兼容,`https://ai.zichuan.xyz/v1`)为唯一上游
|
||||
@@ -57,7 +57,8 @@ GarminHealthLab/
|
||||
│ ├── src/lib/ # day.ts(本地日期)/ metrics.ts(指标注册表)
|
||||
│ ├── src/features.ts # 功能开关(FEATURES.ai)
|
||||
│ └── .env.production # REACT_APP_API_URL=/api(同源,防 Network Error)
|
||||
├── deploy/ # NAS 部署脚本族(S99garmin/start/stop/push/deploy)
|
||||
├── deploy/ # push_oracle.sh 现役;其余(S99garmin/start/stop/
|
||||
│ # push/deploy)是 NAS 时代脚本,已废弃保留参考
|
||||
├── docs/ # 架构 / 开发 / 需求文档
|
||||
├── PROGRESS.md # 进度与部署事实(排查必读)
|
||||
└── README.md # 项目说明 + API 文档
|
||||
@@ -83,24 +84,42 @@ npm run build # client/react-scripts build → client/build/
|
||||
cd backend && .venv/bin/python tests/smoke.py
|
||||
```
|
||||
|
||||
## 部署(生产 = NAS,端口 8124)
|
||||
## 部署(生产 = 甲骨文云主机,2026-09-12 起;此前是 NAS,已下线)
|
||||
|
||||
- **位置**:NAS `192.168.50.64` `/volume1/web/garmin-health-lab`,root 用户跑
|
||||
gunicorn `0.0.0.0:8124`(2 workers / 4 threads / --timeout 300),开机自启走
|
||||
DSM 任务调度器执行 `deploy/S99garmin.sh`。
|
||||
- **一键部署**:本地 `./deploy/push.sh`(tar 经 ssh 同步 backend + deploy +
|
||||
清空重推 client/build + sudo 重启,**校验 gunicorn pid 变化 + health 200**)。
|
||||
前置:先 `npm run build`。
|
||||
- **公网**:NAS frpc → 甲骨文 `http://129.146.26.249:8124`(frp 重连需几秒)。
|
||||
- **DB**:NAS MariaDB 10.11,root 经 socket `/run/mysqld/mysqld10.sock`(或
|
||||
TCP 127.0.0.1:3306),库 `garmin_health_lab`。10.11 dump 含 `/*M!999999`
|
||||
注释、旧客户端会报错,且须 `--default-character-set=utf8mb4` 防中文丢失。
|
||||
- **auth-hub**:client `996aLPw4T5gl-rYZ`;回调注册了 LAN
|
||||
`http://192.168.50.64:8124/auth/callback` 与公网
|
||||
`http://129.146.26.249:8124/auth/callback` 两个地址。
|
||||
- **位置**:`129.146.26.249` `/opt/garmin-health-lab`,**`ubuntu` 用户**跑
|
||||
gunicorn `127.0.0.1:5500`(2 workers / 4 threads / --timeout 300),
|
||||
systemd 单元 `garmin-health-lab.service`(`enabled`,随机器开机自启,
|
||||
`Restart=always`)。和这台机器上其它服务(ai-gateway / auth-hub / fam-edge)
|
||||
同一套约定:`/opt/<项目>` 下独立部署 + 独立 venv + Caddy 按子域名反代。
|
||||
- **公网**:`https://garmin.zichuan.xyz` → Caddy → `127.0.0.1:5500`。
|
||||
DNS(腾讯云 DNSPod,A 记录)与 TLS(Caddy 自动签发)都已配好。
|
||||
~~旧的 `http://129.146.26.249:8124`~~ 已下线(走 NAS frpc 转发,隧道已拆)。
|
||||
- **一键部署**:本地 `./deploy/push_oracle.sh`(tar 经 ssh key 认证同步
|
||||
backend + 清空重推 client/build + pip install + systemctl restart,
|
||||
**校验 main PID 变化 + health 200**)。前置:先 `npm run build`。
|
||||
`deploy/push.sh` / `start.sh` / `stop.sh` / `S99garmin.sh` / `deploy.sh`
|
||||
是 NAS 时代的脚本,已废弃保留仅供参考。
|
||||
- **DB**:甲骨文本机 MariaDB 10.3.39(`127.0.0.1:3306`),独立账号
|
||||
`garmin`(**注意**:`garmin@localhost` 与 `garmin@127.0.0.1` 是两个不同账号,
|
||||
必须同密码建两份,否则 TCP 连接用的是另一个密码),库 `garmin_health_lab`。
|
||||
和其它项目(`chat_relay`、`zhongyuan`)共用同一个 MariaDB 实例,各自独立库
|
||||
独立账号。**这台机器磁盘 96% 已满**,改动前留意剩余空间。
|
||||
- **AI 网关**:`AI_GATEWAY_BASE_URL` 现在是**本地回环** `http://127.0.0.1:5100/v1`
|
||||
(不再经 Caddy/公网 —— 网关和这个服务同机了)。
|
||||
- **auth-hub**:client `996aLPw4T5gl-rYZ`;回调只保留
|
||||
`https://garmin.zichuan.xyz/auth/callback` 一条(NAS/旧公网端口那几条已用
|
||||
`manage_clients remove-redirect-uri` 清掉)。改注册用
|
||||
`/opt/auth-hub` 下 `PYTHONPATH=/opt/auth-hub/src venv/bin/python -m
|
||||
auth_hub.manage_clients`。
|
||||
- **NAS 现状**:`garmin_health_lab` 库已 `DROP DATABASE`(备份在本地
|
||||
`~/Desktop/Work/backups/garmin_health_lab_nas_backup_20260912.sql.gz`,
|
||||
20 张表逐条精确计数核对过一致后才删的),`S99garmin.sh` 开机项已移除,
|
||||
frpc 配置里 `garmin-health` 转发段已删(`gitea`/`wordpress`/`fam-core`/
|
||||
`nexusai` 那几条没动——**Gitea 还在 NAS 上,这个仓库的 git remote 仍然指
|
||||
向它**,这次迁移只搬了应用和数据,没搬源码托管)。
|
||||
- **部署/排障前**:先读 `PROGRESS.md` 与 `deploy/` 脚本确认事实(曾经凭旧记忆
|
||||
断言"无线上环境"而误判)。服务以 root 运行:重启用 sudo,日志
|
||||
`logs/error.log`、`logs/access.log` 是 root 所有。
|
||||
断言"无线上环境"而误判,后来又把"生产在 NAS"当成默认事实——**两次都错在
|
||||
没有先查,部署位置是会变的**)。
|
||||
|
||||
## 关键约定与坑(写代码/改样式前看)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user