235 lines
6.7 KiB
Markdown
235 lines
6.7 KiB
Markdown
# Server B MySQL 与 Redis Runbook
|
||
|
||
> 对应任务:S04
|
||
> 完成日期:2026-06-20
|
||
> 环境:本地开发 Server B
|
||
|
||
## 1. 版本与状态
|
||
|
||
| 服务 | 固定版本 | 监听 |
|
||
| --- | --- | --- |
|
||
| MySQL | 8.0.46-0ubuntu0.24.04.2 | 127.0.0.1:3306、127.0.0.1:33060 |
|
||
| Redis | 7.0.15-1ubuntu0.24.04.4 | 127.0.0.1:6379、100.90.90.91:6379 |
|
||
|
||
固定包:
|
||
|
||
```bash
|
||
apt-mark showhold | grep -E 'mysql|redis'
|
||
```
|
||
|
||
更新前必须先阅读安全公告、备份并执行恢复演练,然后显式 `apt-mark unhold`。不要长期忽略安全更新。
|
||
|
||
版本清单位于:
|
||
|
||
- B:`/etc/lisglosips/versions.env`
|
||
- 仓库:`infra/server-b/s04/versions.env`
|
||
|
||
## 2. 数据目录
|
||
|
||
开发服务器没有独立数据盘。实际数据写入:
|
||
|
||
- `/data/mysql`
|
||
- `/data/redis`
|
||
|
||
为兼容 Ubuntu 包、AppArmor 和 systemd,使用 bind mount 保留标准服务路径:
|
||
|
||
```fstab
|
||
/data/mysql /var/lib/mysql none bind 0 0
|
||
/data/redis /var/lib/redis none bind 0 0
|
||
```
|
||
|
||
服务分别依赖 `var-lib-mysql.mount` 和 `var-lib-redis.mount`。迁移阿里云时必须改用独立数据盘,不能直接复制本地根盘布局。
|
||
|
||
## 3. MySQL 基线
|
||
|
||
配置:`/etc/mysql/mysql.conf.d/99-lisglosips.cnf`
|
||
|
||
- 仅绑定回环地址;
|
||
- 业务库:`lisglosips`,utf8mb4;
|
||
- binlog 已启用,格式 ROW,保留 7 天;
|
||
- `sync_binlog=1`;
|
||
- `innodb_flush_log_at_trx_commit=1`;
|
||
- 数据库默认时区 UTC;
|
||
- 禁止 `local_infile` 和 DNS 主机名解析;
|
||
- 慢查询阈值 1 秒;
|
||
- InnoDB buffer pool 1 GiB,最大连接数 200。
|
||
|
||
账号:
|
||
|
||
| 账号 | 来源 | 权限 |
|
||
| --- | --- | --- |
|
||
| lisglosips_app | 127.0.0.1 | SELECT/INSERT/UPDATE/DELETE/EXECUTE |
|
||
| lisglosips_migrate | 127.0.0.1 | `lisglosips.*` 全权限,用于迁移 |
|
||
|
||
应用账号不能 DDL;S04 已用实际 ALTER 拒绝测试验证。
|
||
|
||
## 4. Redis 基线
|
||
|
||
配置:
|
||
|
||
- `/etc/redis/redis-lisglosips.conf`
|
||
- `/etc/redis/users.acl`
|
||
|
||
关键策略:
|
||
|
||
- protected mode 开启;
|
||
- AOF everysec 与 RDB 快照同时启用;
|
||
- 最大内存 1536 MiB;
|
||
- `maxmemory-policy=noeviction`,业务热数据和 Stream 不静默淘汰;
|
||
- 默认用户关闭;
|
||
- `lisglosips` 允许业务命令但移除 dangerous 类命令;
|
||
- `lisglo-backup` 仅允许 PING、INFO、BGSAVE、LASTSAVE。
|
||
|
||
Redis 绑定 Tailscale 地址。`lisglosips-tailscale-ready.service` 会先等待 100.90.90.91/32 出现,避免 Redis 开机首次启动竞态。
|
||
|
||
## 5. 凭据
|
||
|
||
本地 DPAPI 加密文件:
|
||
|
||
`.codex-private/SERVICE_CREDENTIALS.clixml`
|
||
|
||
包含:
|
||
|
||
- MYSQL_APP
|
||
- MYSQL_MIGRATE
|
||
- REDIS_APP
|
||
- REDIS_BACKUP
|
||
|
||
B 机:
|
||
|
||
| 文件 | 权限 |
|
||
| --- | --- |
|
||
| `/etc/lisglosips/secrets/mysql-app.env` | root:lisglosips 0640 |
|
||
| `/etc/lisglosips/secrets/mysql-migrate.env` | root:root 0600 |
|
||
| `/etc/lisglosips/secrets/redis.env` | root:lisglosips 0640 |
|
||
| `/etc/lisglosips/secrets/redis-backup.env` | root:root 0600 |
|
||
| `/etc/redis/users.acl` | root:redis 0640 |
|
||
|
||
禁止在聊天、日志、状态文件、仓库或命令参数中输出密码。
|
||
|
||
## 6. 网络安全
|
||
|
||
- MySQL 不允许远程连接。
|
||
- Redis 仅允许 A 的 Tailscale IP 100.90.90.90 通过 B 的 nftables 访问。
|
||
- T 对 3306/6379 的连接已验证为超时拒绝。
|
||
- A 第一次访问 B 时可能需要先建立 Tailscale direct 路径:
|
||
|
||
```bash
|
||
tailscale ping --c 1 100.90.90.91
|
||
```
|
||
|
||
稳态 direct 后 Redis 认证连接正常。
|
||
|
||
## 7. 自动备份
|
||
|
||
脚本:
|
||
|
||
- `/usr/local/sbin/lisglosips-mysql-backup`
|
||
- `/usr/local/sbin/lisglosips-redis-backup`
|
||
|
||
systemd:
|
||
|
||
- `lisglosips-backup.service`
|
||
- `lisglosips-backup.timer`
|
||
|
||
每天 03:15 执行,随机延迟最多 15 分钟,保留 14 天。
|
||
|
||
备份目录:
|
||
|
||
```text
|
||
/data/backups/mysql/YYYYMMDDTHHMMSSZ/
|
||
all-databases.sql.gz
|
||
lisglosips.sql.gz
|
||
metadata.tsv
|
||
SHA256SUMS
|
||
|
||
/data/backups/redis/YYYYMMDDTHHMMSSZ/
|
||
dump.rdb
|
||
redis-check-rdb.txt
|
||
metadata.txt
|
||
SHA256SUMS
|
||
```
|
||
|
||
首次有效备份:`20260620T120955Z`。
|
||
|
||
检查:
|
||
|
||
```bash
|
||
sudo systemctl start lisglosips-backup.service
|
||
sudo systemctl show -p Result lisglosips-backup.service
|
||
sudo systemctl list-timers lisglosips-backup.timer
|
||
cd /data/backups/mysql/LATEST_DIRECTORY && sudo sha256sum -c SHA256SUMS
|
||
cd /data/backups/redis/LATEST_DIRECTORY && sudo sha256sum -c SHA256SUMS
|
||
```
|
||
|
||
MySQL 全库备份包含账号密码哈希,只允许 root 读取。Redis ACL 明文密码不进入自动备份,灾难恢复时从 DPAPI 凭据重新生成。
|
||
|
||
## 8. 恢复
|
||
|
||
### MySQL 业务库
|
||
|
||
先创建空的临时数据库进行验证:
|
||
|
||
```bash
|
||
sudo mysql -e 'CREATE DATABASE lisglosips_restore_test CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;'
|
||
gzip -dc /data/backups/mysql/TIMESTAMP/lisglosips.sql.gz | sudo mysql lisglosips_restore_test
|
||
sudo mysql -e 'SHOW TABLES FROM lisglosips_restore_test;'
|
||
```
|
||
|
||
确认数据后再安排正式恢复窗口。禁止直接将 `all-databases.sql.gz` 覆盖到运行中的生产实例。
|
||
|
||
### Redis RDB
|
||
|
||
将备份 `dump.rdb` 复制到独立临时目录,用 `port 0` 和独立 Unix socket 启动临时 Redis,验证关键 key 后关闭。不要替换运行中实例的 RDB/AOF。
|
||
|
||
S04 已完成:
|
||
|
||
- MySQL 备份后删除源表,恢复到临时库并验证 token;
|
||
- Redis 备份后删除源 key,恢复到独立实例并验证 token;
|
||
- 两类探针和临时实例均已清理。
|
||
|
||
## 9. 健康检查
|
||
|
||
```bash
|
||
systemctl is-active mysql redis-server lisglosips-backup.timer
|
||
mysqladmin --protocol=socket ping
|
||
sudo mysql -e 'SELECT @@version, @@log_bin, @@binlog_format, @@time_zone;'
|
||
sudo findmnt /var/lib/mysql
|
||
sudo findmnt /var/lib/redis
|
||
sudo systemctl show redis-server -p Result -p NRestarts
|
||
sudo journalctl -b -u mysql -u redis-server -p err
|
||
```
|
||
|
||
验收状态:
|
||
|
||
- 重启后 MySQL/Redis active;
|
||
- Redis 首次启动 `NRestarts=0`;
|
||
- 没有 failed systemd unit;
|
||
- AOF 写入和 RDB BGSAVE 均正常;
|
||
- 重启持久化探针通过并已清理。
|
||
|
||
## 10. 回滚
|
||
|
||
S04 前备份:
|
||
|
||
`/var/backups/lisglosips-s04/20260620195847`
|
||
|
||
包含配置基线、迁移前 MySQL/Redis 数据目录压缩包、变更后配置、失败演练样本和 SHA-256 清单。
|
||
|
||
回滚数据目录必须在维护窗口执行:
|
||
|
||
1. 停止 `lisglosips-backup.timer`、MySQL 和 Redis。
|
||
2. 卸载 `/var/lib/mysql`、`/var/lib/redis`。
|
||
3. 恢复 S04 前 fstab。
|
||
4. 将当前数据目录另行归档,不直接覆盖。
|
||
5. 解压 `mysql.pre-s04.tar.gz` 和 `redis.pre-s04.tar.gz` 到 `/var/lib`。
|
||
6. 恢复配置后执行语法检查,再逐个启动服务。
|
||
|
||
不要在没有完整备份与控制台访问的情况下卸载、覆盖或降级数据库包。
|
||
|
||
## 11. 已知事项
|
||
|
||
- 早期一次备份使用绝对校验路径,已移至 S04 备份目录下的 `failed-backups` 留档,不参与恢复。
|
||
- 本地根盘适合开发,不满足生产数据库与录音故障隔离要求。
|
||
- 软件包处于 hold;上线前需建立定期安全更新和预生产验证流程。
|