143 lines
5.5 KiB
Markdown
143 lines
5.5 KiB
Markdown
# S30 备份、Runbook、灰度与上线
|
||
|
||
## 1. 范围
|
||
|
||
当前 S30 面向本地 KVM 开发环境的 V2 闭环冻结与上线演练,不执行真实阿里云切流。阿里云迁移必须在新 VPC、正式 DNS/TLS、独立数据盘和安全组完成后,按本文重新演练。
|
||
|
||
## 2. 冻结清单
|
||
|
||
| 项 | 当前值 |
|
||
| --- | --- |
|
||
| B release | `/opt/lisglosips/releases/s28-v2-20260621220924` |
|
||
| B current | `/opt/lisglosips/current` 指向当前 release |
|
||
| A OpenSIPS | `/etc/opensips/opensips.cfg` |
|
||
| T 测试脚本 | `/opt/lisglosips-s28/lisglosips-s28-sip.py` |
|
||
| 数据库迁移 | 以 `prisma/migrations/` 和 B 当前库为准 |
|
||
| Redis 配置版本 | 以 `cfg:active_version` 为准 |
|
||
|
||
冻结后只允许以下变更进入上线窗口:
|
||
|
||
- 修复已确认阻塞缺陷;
|
||
- 更新正式域名/TLS/安全组等环境参数;
|
||
- 文档化灰度和回滚记录。
|
||
|
||
## 3. 上线前备份
|
||
|
||
在任何 release 切换、数据库迁移、OpenSIPS 配置替换、Nginx/TLS 调整前执行:
|
||
|
||
```bash
|
||
sudo systemctl start lisglosips-backup.service
|
||
sudo find /data/backups/mysql -mindepth 1 -maxdepth 1 -type d | sort | tail -1
|
||
sudo find /data/backups/redis -mindepth 1 -maxdepth 1 -type d | sort | tail -1
|
||
sudo sha256sum -c /data/backups/mysql/<stamp>/SHA256SUMS
|
||
sudo sha256sum -c /data/backups/redis/<stamp>/SHA256SUMS
|
||
```
|
||
|
||
另外备份:
|
||
|
||
```bash
|
||
sudo install -d -m 0700 /var/backups/lisglosips-s30/<stamp>
|
||
sudo cp -a /etc/lisglosips /etc/nginx /etc/systemd/system/lisglosips@.service /var/backups/lisglosips-s30/<stamp>/
|
||
sudo cp -a /etc/opensips/opensips.cfg /var/backups/lisglosips-s30/<stamp>/opensips.cfg
|
||
```
|
||
|
||
备份目录只允许 root 读取,不复制明文 secret 到仓库或聊天记录。
|
||
|
||
## 4. 恢复演练
|
||
|
||
MySQL 只恢复到隔离临时库:
|
||
|
||
```bash
|
||
sudo mysql -e 'DROP DATABASE IF EXISTS lisglosips_s30_restore; CREATE DATABASE lisglosips_s30_restore CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;'
|
||
gzip -dc /data/backups/mysql/<stamp>/lisglosips.sql.gz | sudo mysql lisglosips_s30_restore
|
||
sudo mysql -e 'SELECT COUNT(*) FROM lisglosips_s30_restore.raw_cdrs;'
|
||
sudo mysql -e 'DROP DATABASE lisglosips_s30_restore;'
|
||
```
|
||
|
||
Redis 只启动隔离临时实例:
|
||
|
||
```bash
|
||
sudo install -d -m 0700 /tmp/lisglosips-s30-redis-restore
|
||
sudo cp /data/backups/redis/<stamp>/dump.rdb /tmp/lisglosips-s30-redis-restore/dump.rdb
|
||
sudo redis-server --dir /tmp/lisglosips-s30-redis-restore --dbfilename dump.rdb --port 0 --unixsocket /tmp/lisglosips-s30-redis.sock --daemonize yes
|
||
sudo redis-cli -s /tmp/lisglosips-s30-redis.sock DBSIZE
|
||
sudo redis-cli -s /tmp/lisglosips-s30-redis.sock SHUTDOWN NOSAVE
|
||
```
|
||
|
||
禁止把备份直接覆盖运行中 `/var/lib/mysql`、`/var/lib/redis`。
|
||
|
||
## 5. 发布顺序
|
||
|
||
1. 记录当前 release、数据库迁移版本、Redis `cfg:active_version`、A OpenSIPS 配置 SHA-256。
|
||
2. 执行 S30 备份与恢复演练。
|
||
3. 上传新 release 到 `/opt/lisglosips/releases/<release-id>`,校验 `package.json`、`pnpm-lock.yaml` 和构建产物。
|
||
4. 执行向前兼容数据库迁移,禁止同窗口不可逆删列。
|
||
5. 原子切换 `/opt/lisglosips/current`。
|
||
6. 重启 `lisglosips@api`、`lisglosips@cdr-worker`、`lisglosips@recording-worker`。
|
||
7. `nginx -t` 后 reload Nginx。
|
||
8. 执行 `infra/server-b/s30/lisglosips-release-preflight.sh`。
|
||
9. 发布 Redis 配置快照并确认 A 使用新版本。
|
||
10. T 发起测试呼叫,按 Call-ID 核对 SIP、CDR、计费、录音、HOMER。
|
||
11. 开始灰度。
|
||
|
||
## 6. 灰度策略
|
||
|
||
本地环境使用 `cus_s28_t` 和 T 专用 UAS 作为灰度对象;生产环境选择一个低风险客户或一条低风险线路。
|
||
|
||
灰度观察项:
|
||
|
||
- SIP 2xx/4xx/5xx 分布;
|
||
- Redis Stream lag 和 pending;
|
||
- CDR 入库与重复扣费;
|
||
- 余额变化和充值幂等;
|
||
- 录音 READY 比例、A tmpfs 使用率;
|
||
- API 5xx、P95/P99;
|
||
- HOMER 是否可按 Call-ID 查询。
|
||
|
||
扩大条件:连续观察 24-72 小时无 P1/P2 缺陷、无 CDR/余额异常、录音搬运无持续积压。
|
||
|
||
## 7. 回滚
|
||
|
||
### B 应用回滚
|
||
|
||
```bash
|
||
sudo infra/server-b/s30/lisglosips-release-rollback.sh /opt/lisglosips/releases/<previous-release>
|
||
```
|
||
|
||
脚本会切换 `current`、重启 API/CDR/Recording Worker、校验 Nginx 并检查 API ready。
|
||
|
||
### Redis 配置回滚
|
||
|
||
切回上一个 `cfg:active_version`,不删除 Stream 或 deadletter。回滚后用 T 呼叫验证 A 已读取旧版本。
|
||
|
||
### OpenSIPS 回滚
|
||
|
||
```bash
|
||
sudo infra/server-a/s30/lisglosips-opensips-config-restore.sh /var/backups/<path>/opensips.cfg
|
||
```
|
||
|
||
脚本会先备份当前配置、执行 `opensips -C`,通过后替换并重启 OpenSIPS。重启会影响现有通话,生产必须放在维护窗口或确认可接受。
|
||
|
||
### 数据库回滚
|
||
|
||
优先发布向前修复迁移;只有在确认不可用且有完整备份时,才进入维护窗口做数据恢复。充值、CDR、审计、录音记录不直接物理删除。
|
||
|
||
### S29 Redis 恢复遗留风险
|
||
|
||
若 B Redis 故障恢复后 A 继续返回 `503 Redis Unavailable`:
|
||
|
||
1. 确认 B `redis-server` active,A 到 B Redis 端口可达。
|
||
2. 重启 A `lisglosips-redis-auth-proxy`。
|
||
3. 若仍失败,维护窗口内重启 A `opensips`。
|
||
4. 记录 Call-ID、A 日志、Redis proxy 日志,作为后续根因修复输入。
|
||
|
||
## 8. 阿里云迁移前阻断项
|
||
|
||
- 正式 DNS/TLS 未完成;
|
||
- A/B 未位于同 VPC 低时延私网;
|
||
- B 未使用独立数据盘承载 MySQL、Redis、录音和监控;
|
||
- 安全组未限制 SSH 管理来源,或禁用了 SSH 密钥登录;
|
||
- 未完成新环境备份恢复演练;
|
||
- 未完成 T 或外部测试端到端呼叫;
|
||
- Redis 恢复后 OpenSIPS 自动恢复风险未纳入告警/Runbook。
|