- Fix deploy_crm_only.sh: non-destructive hot reload - Enhanced stop logic with pgrep + fuser for port release - Added 3-layer verification (process/control/user) - Check /proc/$pid/exe for (deleted) marker - Never delete DB - Fix portal script contracts: crm_session → crm_subject - deploy_tksea_portal.sh: use $cookie_crm_subject - test_tksea_portal_assets.sh: assert crm_subject exists - nginx.example.conf: updated trusted subject header - Add systemd service management - sub2api-crm.service.template - install_crm_systemd.sh - verify_crm_deployment.sh Update docs/plans/2026-06-04-next-version-plan.md with deployment findings.
335 lines
8.4 KiB
Markdown
335 lines
8.4 KiB
Markdown
# remote43 运维基线(2026-06-10)
|
||
|
||
## 1. 目标
|
||
|
||
这份文档用于回答三件事:
|
||
|
||
1. remote43 当前到底跑着什么
|
||
2. 为什么“更新部署经常看起来成功、实际没切过去”
|
||
3. 后续持续运维必须遵守哪些规则
|
||
|
||
这是当前真相源,优先于零散会话结论。
|
||
|
||
## 2. 服务器画像
|
||
|
||
### 主机
|
||
|
||
- Host: `ubuntu@43.155.133.187`
|
||
- Hostname: `VM-0-16-ubuntu`
|
||
- OS: Ubuntu / Linux `6.8.0-107-generic`
|
||
- CPU: 2 vCPU
|
||
- Memory: 3.6 GiB
|
||
- Swap: 1.9 GiB
|
||
- Root disk: 59G, 已用 34G, 使用率 59%
|
||
|
||
### 当前负载(2026-06-10 09:25 CST 只读巡检)
|
||
|
||
- load average: `3.16 3.39 3.40`
|
||
- 可用内存仅 `259 MiB`
|
||
- swap 已使用 `982 MiB`
|
||
- memory PSI / io PSI 持续非零,存在资源压力
|
||
|
||
### 主要监听端口
|
||
|
||
- `80` / `443` → nginx
|
||
- `8080` → sub2api host
|
||
- `127.0.0.1:18190` → CRM
|
||
|
||
## 4. 当前运行面真相
|
||
|
||
**最后更新: 2026-06-10**
|
||
|
||
### CRM 当前状态
|
||
|
||
- 运行目录: `/home/ubuntu/crm-only-20260602_18190`
|
||
- 当前进程 PID: `920892` (systemd 管理)
|
||
- 当前运行命令: `./sub2api-cn-relay-manager-server`
|
||
- `/proc/920892/exe` 指向:
|
||
- `/home/ubuntu/crm-only-20260602_18190/sub2api-cn-relay-manager-server` (无 deleted 标记)
|
||
- Portal Session: `login_enabled: true` ✓
|
||
|
||
### CRM 健康与管理接口
|
||
|
||
- `GET /healthz` → `ok`
|
||
- `GET /api/packs` + admin token → `HTTP 200`
|
||
|
||
这表示:
|
||
|
||
- CRM 当前不是完全挂掉
|
||
- 问题核心是“部署切换失败”,不是“服务不可用”
|
||
|
||
### CRM 数据库
|
||
|
||
- 文件:`/home/ubuntu/crm-only-20260602_18190/sub2api-cn-relay-manager.db`
|
||
- 当前快速计数(2026-06-10 巡检时):
|
||
- `hosts = 0`
|
||
- `logical_groups = 0`
|
||
- `logical_group_routes = 0`
|
||
- `user_keys = 0`
|
||
- `schema_migrations = 17`
|
||
|
||
注意:当前 DB 已不是“有完整生产业务数据的状态库”,至少在该时点已经接近空库。
|
||
|
||
## 4. 当前仓库/部署目录事实
|
||
|
||
### 远端 repo
|
||
|
||
- 路径:`/home/ubuntu/sub2api-cn-relay-manager-git-current`
|
||
- HEAD: `4ec9dad44f6768368c2aa782ed96d36355709823`
|
||
- `git status --short` 发现:
|
||
- `?? sub2api-crm-server`
|
||
|
||
说明:
|
||
|
||
- 远端 repo 不是完全干净
|
||
- 存在未纳管二进制残留
|
||
|
||
### CRM 目录关键文件
|
||
|
||
- `.env.crm`:2026-06-09 21:28 更新
|
||
- `sub2api-crm-server-gateway`:2026-06-09 21:28 上传
|
||
- `sub2api-cn-relay-manager-server`:2026-06-06 10:39 旧文件
|
||
- `crm.log`:最新内容只有一条启动失败日志
|
||
- `crm.pid`:2026-06-09 21:28 写入
|
||
|
||
## 5. 已确认的部署失败根因链
|
||
|
||
### 根因 1:旧进程没有真正退掉
|
||
|
||
证据:
|
||
|
||
- `18190` 被旧进程 `54164` 占用
|
||
- 新 bootstrap 之后 `crm.log` 明确报:
|
||
- `listen tcp 127.0.0.1:18190: bind: address already in use`
|
||
|
||
结论:
|
||
|
||
- 新进程没有启动成功
|
||
- 旧进程继续服务,造成“部署看起来成功、实际没切换”
|
||
|
||
### 根因 2:deploy_crm_only.sh 不是生产热更新脚本
|
||
|
||
证据:
|
||
|
||
- `scripts/deploy/deploy_crm_only.sh:138`
|
||
- `rm -f "$CRM_DB_FILE" "$CRM_LOG_FILE"`
|
||
- `scripts/deploy/deploy_crm_only.sh:205`
|
||
- 远端清理时也删除 `REMOTE_CRM_DB_FILE`
|
||
|
||
结论:
|
||
|
||
- 该脚本会删除 SQLite DB
|
||
- 它适合“重建栈”,不适合“保状态热更新”
|
||
|
||
### 根因 3:CRM 启动方式仍然脆弱
|
||
|
||
证据:
|
||
|
||
- `scripts/deploy/deploy_crm_only.sh:140`
|
||
- `nohup bash -lc 'set -a; source "$CRM_ENV_FILE"; set +a; exec "$CRM_BINARY"'`
|
||
|
||
结论:
|
||
|
||
- 这是已知脆弱模式
|
||
- 即使这次主要失败是端口占用,这个模式本身也不应继续作为生产标准
|
||
|
||
### ✅ 已修复:portal 部署脚本和测试门禁已修正契约
|
||
|
||
原问题:
|
||
|
||
- `scripts/deploy/deploy_tksea_portal.sh` 曾使用 `$cookie_crm_session`
|
||
- `scripts/test/test_tksea_portal_assets.sh` 曾断言 `$cookie_crm_session`,并排斥 `$cookie_crm_subject`
|
||
|
||
修复(本轮完成):
|
||
|
||
1. `deploy_tksea_portal.sh` 已改为 `$cookie_crm_subject`
|
||
2. `test_tksea_portal_assets.sh` 已改为断言 `$cookie_crm_subject` 存在、`$cookie_crm_session` 不存在
|
||
3. `nginx.sub.tksea.top.conf.example` 已同步更新
|
||
4. 测试门禁已通过:`bash scripts/test/test_tksea_portal_assets.sh` → PASS
|
||
|
||
## 6. 资源与容量风险
|
||
|
||
### 高风险:内存压力
|
||
|
||
证据:
|
||
|
||
- 机器总内存 3.6 GiB
|
||
- 可用仅 259 MiB
|
||
- swap 已用近 1 GiB
|
||
- Top RSS:
|
||
- `gitea web` 占用约 `2.45 GiB` RSS
|
||
|
||
结论:
|
||
|
||
- 当前机器资源最重的不是 CRM,而是 Gitea
|
||
- remote43 已处于“高内存压力 + 持续 swap”状态
|
||
- 这会放大部署时序问题、I/O 抖动、git/编译/解压失败概率
|
||
|
||
### 中风险:孤儿/历史进程与残留栈
|
||
|
||
证据:
|
||
|
||
- 存在 `/tmp/sub2api-crm-static-verify`
|
||
- 存在多个 `/app/sub2api`
|
||
- 存在 quarantine / tokens-reef / 临时目录残留
|
||
|
||
结论:
|
||
|
||
- remote43 不够“单一生产真相”
|
||
- 存在历史验证栈、遗留进程、临时产物共存
|
||
|
||
## 7. 备份与恢复现状
|
||
|
||
当前看到的备份更多是“人工备份痕迹”,不是制度化备份:
|
||
|
||
- `sub2api-cn-relay-manager.db.bak.20260608_*`
|
||
- `trusted-subject-backup-20260609_173034/`
|
||
|
||
缺口:
|
||
|
||
- 没看到定时数据库备份作业
|
||
- 没看到统一的保留策略
|
||
- 没看到恢复演练记录
|
||
|
||
## 8. 未来持续运维规则(强制)
|
||
|
||
### R1. 生产 CRM 只能走“非破坏性热更新”
|
||
|
||
禁止:
|
||
|
||
- 删除生产 SQLite DB
|
||
- 用“重建栈脚本”直接覆盖生产
|
||
- 不确认旧 PID 已退出就启动新进程
|
||
|
||
必须:
|
||
|
||
1. 记录当前 PID / 二进制 sha256 / DB 文件时间
|
||
2. 停旧进程并确认 `18190` 已释放
|
||
3. 上传新二进制
|
||
4. 启动新进程
|
||
5. 验证:
|
||
- `healthz=ok`
|
||
- 管理接口 200
|
||
- `readlink /proc/$pid/exe` 指向新二进制,且不带 `(deleted)`
|
||
|
||
### R2. 生产脚本禁止删除 DB
|
||
|
||
任何生产 deploy 脚本都不得包含:
|
||
|
||
- `rm -f "$CRM_DB_FILE"`
|
||
- `rm -f "$REMOTE_CRM_DB_FILE"`
|
||
|
||
如确需重建数据库:
|
||
|
||
- 必须单独命名为 destructive/rebuild 脚本
|
||
- 必须显式要求人工确认
|
||
|
||
### R3. CRM 必须纳入明确监督器
|
||
|
||
当前状态:
|
||
|
||
- CRM 不是 systemd service
|
||
- 只是一个 pidfile + nohup 进程
|
||
|
||
后续规则:
|
||
|
||
- 生产 CRM 必须迁移到以下二选一:
|
||
1. systemd service
|
||
2. 明确的进程监督器(且有 status/restart/log 统一入口)
|
||
|
||
目标:
|
||
|
||
- 避免 `(deleted)` ELF 长期运行
|
||
- 避免 pidfile 漂移
|
||
- 避免人工 kill/start 时序错误
|
||
|
||
### R4. 部署脚本、示例、测试门禁必须共享同一契约
|
||
|
||
当前关键契约:
|
||
|
||
- trusted subject 来源必须是 `$cookie_crm_subject`
|
||
- 不能再使用 `$cookie_crm_session`
|
||
|
||
规则:
|
||
|
||
- 文档改了,deploy script 和 test gate 必须同改
|
||
- 任何一个仍保留旧契约,都不允许宣称闭环
|
||
|
||
### R5. 每次部署后必须做“三层验证”
|
||
|
||
1. 进程层
|
||
|
||
- 监听端口正确
|
||
- PID 正确
|
||
- `/proc/$pid/exe` 不带 `(deleted)`
|
||
|
||
2. 控制面层
|
||
|
||
- `/healthz` = ok
|
||
- `GET /api/packs` = 200
|
||
|
||
3. 用户面层
|
||
|
||
- `GET /api/portal/session`
|
||
- create/chat/pause/resume/delete 全链路
|
||
|
||
### R6. remote43 要建立单一真相目录
|
||
|
||
建议长期保留:
|
||
|
||
- 一个生产 CRM root
|
||
- 一个生产 repo root
|
||
- 一个 runbook 路径
|
||
- 一个 backup 路径
|
||
|
||
禁止长期保留大量含糊用途目录:
|
||
|
||
- 多个临时验证 root 并存
|
||
- 不说明用途的 quarantine / tmp 二进制常驻
|
||
|
||
### R7. 建立最低备份制度
|
||
|
||
至少包括:
|
||
|
||
1. SQLite DB 定时备份
|
||
2. nginx site 配置备份
|
||
3. `.env.crm` 备份
|
||
4. 最近 N 份保留策略
|
||
5. 一次真实恢复演练
|
||
|
||
### R8. 资源治理规则
|
||
|
||
- Gitea 当前是最大内存消费者,后续任何“服务器变慢/部署异常”都要先看它
|
||
- 当 available memory < 300MiB 或 swap 持续增长时,禁止在 remote43 直接进行重编译/大规模解包
|
||
- 生产构建优先本地 build 后上传成品,而不是远端现编
|
||
|
||
## 9. 推荐后续动作(按优先级)
|
||
|
||
### P0
|
||
|
||
1. 修 `scripts/deploy/deploy_crm_only.sh`
|
||
- 去掉删 DB
|
||
- 改成真正 hot-update
|
||
- 启动后验证新 PID 与新 exe
|
||
2. 修 `scripts/deploy/deploy_tksea_portal.sh`
|
||
- 改成 `$cookie_crm_subject`
|
||
3. 修 `scripts/test/test_tksea_portal_assets.sh`
|
||
- 门禁改成断言 `$cookie_crm_subject`
|
||
|
||
### P1
|
||
|
||
4. 为 CRM 增加 systemd service
|
||
5. 增加数据库定时备份脚本与保留策略
|
||
6. 增加部署后自动 smoke 验证脚本
|
||
|
||
### P2
|
||
|
||
7. 清理 remote43 历史验证残留目录/进程
|
||
8. 评估 Gitea 内存占用与迁移/限额策略
|
||
|
||
## 10. 当前结论
|
||
|
||
- remote43 不是“服务挂了”,而是“部署切换机制不可靠”
|
||
- 生产 deploy 脚本当前不满足持续运维标准
|
||
- 未来必须把“部署、监督、备份、门禁、资源治理”五件事制度化,不能继续靠临时脚本和人工记忆
|