|
|
cbff292551
|
feat(切换): compose 支持「只换前后端」,接着用旧栈的 postgres/redis
演练把一件事盖住了:当时是把生产 dump 恢复进 `OJ2/data/postgres` 的,
所以没人发现新 compose 在 `OJ2/docker/` 下,`../data` 解析出来是 `OJ2/data`,
而旧栈用的是 `<部署目录>/data`(服务器上是 `/root/OJDeploy/data`)。
照原手册切过去,postgres 会在一个空目录上初始化一个全新的空库 —— 站点起得来,
但没有用户没有题、判题全挂、题面图片 404。旧数据完好,回滚正常,但当天会白吓一场。
## 改法
三组 env 旋钮,默认值保持原样,不影响本机和演练那条路:
DATA_DIR 所有数据卷的根,默认 ../data
DB_HOST/PORT 默认 oj-postgres:5432
REDIS_HOST/PORT 默认 oj-redis:6379
postgres 和 redis 挪进 `profiles: ["local-data"]`,默认不起 —— 否则会跟旧栈
那两个抢 5445 / 5446。配套给 depends_on 加 `required: false`:实测严格的
depends_on 碰上未启用的 profile 会让整个 project 直接 invalid,不是可选项。
代价写进注释了:自带数据形态下 postgres 起不来时 compose 只警告不中止。
给 api / worker 加 host-gateway 映射,DB_HOST 填 host.docker.internal 就行,
不用去猜 docker0 的网段。数据库流量不出本机。
school 那套的 7 个挂载点同样换成 DATA_DIR —— 机房那台也有自己的旧数据目录,
测试点和题面图片都在里面,同一个坑。
## 验证
用 docs/specs/schema.sql 起了个发布在宿主机 5445 的 postgres 冒充旧栈:
正好 4 个容器(没有 postgres/redis)、oj-api healthy、首页与 /api/site
/api/problems 200、未登录进后台 401。读写两个方向都验了 —— 那个库的
pg_stat_activity 里有来自 172.17.0.1 的 postgres.js 连接,judge_server 表里
也出现了新判题机写进去的心跳行。
四份 compose 的 `config -q` 全通过。
手册第三、四、六节按这个形态重写:停旧栈改成只 stop oj-backend / oj-judge
(旧判题机会争 data/judge_server/run,旧 backend 占着 8080),回滚变成把这两个
再 start 起来,数据库进程全程不停。
**DATA_DIR 漏填不会报错**(它有默认值),是切换当天唯一会静默走歪的地方,
手册里给了 `config | grep source:` 的自查和两种症状的区分。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-16 08:57:25 -06:00 |
|
|
|
a47e051a49
|
docs(阶段5): 补验 WebSocket 经 Caddy 与机房那套 compose
演练报告里原来有两块是没验过的,补上:
## WebSocket 经 Caddy
学生盯着「判题中…」变成结果就靠这条路,而它经过 Caddy 的 handle /ws/*,
是配置最容易写错、又只在生产才暴露的一段。实测 upgrade 成功,301ms 内
收到两条推送:judging → finished(AC)。
## 机房那套 compose.school.yml
和服务器那套差别不小(没有 postgres、连远程库、端口 81、COOKIE_SECURE=false),
之前一次都没跑过。留下 oj-postgres 当「远程库」、其余换成 school 栈跑了一遍:
连库、首页、题目列表、登录、WS、完整判题全通。
其中特意验了 **Cookie 没带 Secure** —— 带了的话机房(http 直连 IP)会出现
「登录成功但立刻又变未登录」,是那种看起来毫无头绪的故障。
顺带确认机房的拓扑是「本地 Redis + 本地判题沙箱 + 远程库」,
判题不跨公网,只有数据库查询走公网。
演练用的是 docs/specs/schema.sql 只灌结构,盘上不留学生数据;跑完已清干净。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-08 03:33:00 -06:00 |
|
|
|
fb22b7d49f
|
docs(阶段5): 用生产快照跑完整切换演练
演练用 compose.debian.yml **本身**在本机 Docker 里跑,不是简化版。
数据是 2026-08-07 的 pg_dumpall 快照:1710 用户 / 956 题 / 123140 提交。
## 出口标准达成
停旧栈 11s,起新栈 34s(镜像预先构建好),全链路验证约 2 分钟 ——
**停机不到 1 分钟**,远在 30 分钟内。真正的时间风险在构建镜像(首次约 5 分钟),
所以手册里第一条就是「镜像必须在停机窗口之前构建好」。
验证到位的:首页、站点配置、题目列表、标签、公告、登录(argon2 新哈希和
Django pbkdf2 旧哈希都支持)、个人页、排行榜、后台四个接口、判题机自动注册,
以及**完整判题**(提交 Python A+B → AC,1.2 秒,两个测试点全过)。
## 两件原以为要做、实测不用做的事
- **不需要任何 DDL**:生产 dump 和新后端在用的库逐列对比,两边都是 278 列,
零差异。新后端直接跑在现有结构上。
- **不需要重置序列**:我在 phase3-coverage.md 里记的那条「切换必做:重置序列」
**是错的**,来自我手工按显式 id 导入、又没补 setval 的本地库。真实的
pg_dumpall 带 30 条 setval,且把快照里所有序列和 max(id) 逐个对过,错位 0 个。
已在原文档上标注更正,没有删掉原文 —— 错误结论本身也是信息。
## 回滚保证已实测
新栈跑完登录、提交、判题之后,再和生产 dump 比一次结构:逐列一致,零差异。
加上数据目录布局照抄旧后端,回滚 = 停新栈 + 起旧栈,约 20 秒,不动任何数据。
(未实测的部分也写明了:本机没构建旧 Django 镜像,「起旧栈」这一步没跑过。)
## 演练抓到的真问题
**pg_dumpall 备份会覆盖数据库口令。** 恢复完快照,新后端立刻报
`password authentication failed` —— 因为 dump 里带
`ALTER ROLE onlinejudge ... PASSWORD 'md5…'`,把角色口令覆盖成了备份时生产的那个。
正常切换不受影响(根本不恢复备份),但灾难恢复时这一条不写下来,
现场会被一个看起来毫不相干的报错卡住。
**恢复备份前必须先停应用**,否则 dump 里的 DROP DATABASE 失败。演练时因为
目标库是空的,数据照样进去了 —— 那是运气,目标库有数据就是满屏主键冲突。
## 镜像体积没达标,写明了原因
api 镜像 487MB,设计文档写的是「数十 MB」。一半以上(269MB)是 clang-format
拖进来的 LLVM,光 libLLVM.so 就 124MB。旧 Python 镜像同样装了 clang-format,
所以新镜像仍明显更小,但当初估「数十 MB」时没把它算进去。
瘦身路径也记了(换静态 clang-format 可砍 265MB),暂不做。
## 清理
演练在 data/postgres 留下了一份完整的生产数据副本,含 1710 名学生的
raw_password 明文列,已删除。手册里留了提醒 —— 那不是测试数据。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-08 02:13:59 -06:00 |
|