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>
This commit is contained in:
2026-08-16 08:57:25 -06:00
parent 2c6f8d11f3
commit cbff292551
5 changed files with 274 additions and 46 deletions

View File

@@ -10,6 +10,10 @@
# 旧后端的 Channels 也是这样,不是回归;
# - **切换那天两边都要切。** 只切一边的话,另一边的旧后端仍在读写同一个库,
# 而库结构已经按新后端迁过了。
#
# ⚠️ `DATA_DIR` 默认值 `../data` 解析出来是 **`OJ2/data`**,不是机房部署目录的 `data/`。
# 测试点(`data/backend/test_case`)和题面图片(`data/backend/public/upload`)都在旧目录里,
# 不设 `DATA_DIR` 就会挂一堆空目录上去:判题全错、图片 404。**沿用旧数据必须设它。**
services:
oj-redis:
@@ -17,7 +21,7 @@ services:
container_name: oj-redis
restart: always
volumes:
- ../data/redis:/data
- ${DATA_DIR:-../data}/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
@@ -39,9 +43,9 @@ services:
tmpfs:
- /tmp
volumes:
- ../data/backend/test_case:/test_case:ro
- ../data/judge_server/log:/log
- ../data/judge_server/run:/judger
- ${DATA_DIR:-../data}/backend/test_case:/test_case:ro
- ${DATA_DIR:-../data}/judge_server/log:/log
- ${DATA_DIR:-../data}/judge_server/run:/judger
environment:
SERVICE_URL: http://oj-judge:8080
BACKEND_URL: http://oj-api:3000/api/judge-server/heartbeat
@@ -61,7 +65,7 @@ services:
oj-redis:
condition: service_healthy
volumes:
- ../data/backend:/data
- ${DATA_DIR:-../data}/backend:/data
environment: &api-env
# 库在服务器上走公网。DB_HOST 默认值就是服务器地址,换机器改 env 文件
DATABASE_URL: postgres://onlinejudge:${POSTGRES_PASSWORD:?}@${DB_HOST:-150.158.29.156}:${DB_PORT:-5445}/onlinejudge
@@ -89,7 +93,7 @@ services:
depends_on:
- oj-api
volumes:
- ../data/backend:/data
- ${DATA_DIR:-../data}/backend:/data
environment: *api-env
command: ["oj2-api", "worker"]
mem_limit: 2g
@@ -105,7 +109,7 @@ services:
depends_on:
- oj-api
volumes:
- ../data/backend/log:/data/log
- ${DATA_DIR:-../data}/backend/log:/data/log
ports:
- "81:8000"
mem_limit: 256m