Deploy / deploy (push) Canceled after 0s
- access token 是 15 分钟的 JWT,走 Authorization: Bearer;refresh token 7 天,每次换都轮换 - 退出登录、改密码、禁用账号仍然立刻生效:每个请求核对 Redis 会话和库里新加的 user.token_version - 在服务器后台改密码 / 禁用,机房那边登着的也会一起下线(原来两边 Redis 分开,管不到) - WebSocket 握手借子协议带 token;JWT 密钥存在本站 Redis,部署不用加配置 - 去掉 COOKIE_SECURE;上线后所有人要重新登录一次 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
198 lines
8.1 KiB
YAML
198 lines
8.1 KiB
YAML
# 服务器(oj.xuyue.cc)。数据库在这里,机房那套连的就是这里的 5445。
|
||
#
|
||
# docker/deploy.sh # 平时走这个(自检 → 构建 → 迁移 → 起栈 → 冒烟)
|
||
#
|
||
# 构建上下文是仓库根,所以 build.context 写 ..(相对本文件)。
|
||
#
|
||
# **服务器上的全部容器都由这一个文件起**,包括 postgres 和 redis。以前库和 redis 是旧栈
|
||
# 那份 /root/OJDeploy/docker-compose.yml 起的、这里通过 DB_HOST 外接过去,升级它们就得去
|
||
# 改那份文件;2026-10 起收了进来(搬家用 docker/move-db-into-oj2.sh,一次性的)。
|
||
#
|
||
# ⚠️ `DATA_DIR` 默认值 `../data` 解析出来是 **`OJ2/data`**,不是部署目录的 `data/`。
|
||
# 不设它的话 postgres 会在空目录上初始化一个全新的空库,测试点和题面图片也全都不在,
|
||
# 而且**不报错**。`deploy.sh` 为此专门设了自检。
|
||
|
||
services:
|
||
oj-postgres:
|
||
image: postgres:18-alpine
|
||
container_name: oj-postgres
|
||
restart: always
|
||
# 18 起镜像的数据目录是 /var/lib/postgresql/18/docker,挂载点要是上一级,
|
||
# 还挂 .../data 的话 18 直接拒绝启动。宿主机目录叫 `postgresql/`,和旧栈 16 的
|
||
# `postgres/` 分开:18 读不了 16 的目录,分开放才留得住老库做回退
|
||
volumes:
|
||
- ${DATA_DIR:-../data}/postgresql:/var/lib/postgresql
|
||
environment:
|
||
POSTGRES_DB: onlinejudge
|
||
POSTGRES_USER: onlinejudge
|
||
# 只在空目录上初始化时用一次,之后改它不会改库里的口令(要 ALTER ROLE)。
|
||
# 这个账号是超级用户、端口又对公网开着,必须是 openssl rand -hex 32 那种强口令
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?请在 docker/.env 里设置 POSTGRES_PASSWORD}
|
||
# 机房那套要连这个端口,必须对外暴露
|
||
ports:
|
||
- "5445:5432"
|
||
# 这台机器 2 核 7.5G、没有 swap,和 gitea、judge0 等二十多个别的服务挤在一起(2026-10 实测
|
||
# 可用 3.5G)。所以这里的取舍是「别被挤死」而不是「吃满内存」:
|
||
# - 全库 249MB,shared_buffers 512MB 能整库常驻,work_mem 16MB 让统计页的聚合排序不落盘;
|
||
# - oom_score_adj 压低:内存真满了,内核先杀别的,不先杀库;
|
||
# - cpu_shares 加倍:上课一个班同时交题时,查库和网页比判题、比别的服务先拿到 CPU。
|
||
# 这是按比例分、不是封顶,闲的时候判题照样用满两个核;
|
||
# - 两个超时防机房断网:事务开着不动超过 60 秒就断,锁不会一直挂着;
|
||
# TCP 保活把断掉的远端连接从默认两小时缩到两分钟左右才发现。
|
||
command:
|
||
- postgres
|
||
- -c
|
||
- shared_buffers=512MB
|
||
- -c
|
||
- effective_cache_size=2GB
|
||
- -c
|
||
- work_mem=16MB
|
||
- -c
|
||
- maintenance_work_mem=128MB
|
||
- -c
|
||
- idle_in_transaction_session_timeout=60s
|
||
- -c
|
||
- tcp_keepalives_idle=60
|
||
- -c
|
||
- tcp_keepalives_interval=10
|
||
- -c
|
||
- tcp_keepalives_count=6
|
||
# 并行查询的工作区走 /dev/shm,docker 默认只给 64MB,大一点的并行哈希会直接报错
|
||
shm_size: 256m
|
||
oom_score_adj: -500
|
||
cpu_shares: 2048
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U onlinejudge -d onlinejudge"]
|
||
interval: 5s
|
||
timeout: 3s
|
||
retries: 10
|
||
|
||
oj-redis:
|
||
image: redis:8-alpine
|
||
container_name: oj-redis
|
||
restart: always
|
||
# 会话存在这里:谁能连上它,谁就能写一条 session:<token> 冒充超管。所以必须带密码,
|
||
# 端口也只发布在本机(api / worker 走 compose 网络连 oj-redis,用不着宿主机端口)。
|
||
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:?}"]
|
||
environment:
|
||
# redis-cli 认这个变量,healthcheck 和 docker exec 进来的 redis-cli 都不用再带 -a
|
||
REDISCLI_AUTH: ${REDIS_PASSWORD:?}
|
||
volumes:
|
||
- ${DATA_DIR:-../data}/redis:/data
|
||
ports:
|
||
- "127.0.0.1:5446:6379"
|
||
healthcheck:
|
||
test: ["CMD", "redis-cli", "ping"]
|
||
interval: 5s
|
||
timeout: 3s
|
||
retries: 10
|
||
|
||
oj-judge:
|
||
# 自己构建的判题沙箱(上游 JudgeServer 1.6.1 + 新工具链,见 docker/judge/)。
|
||
# 上游停更在 2024-04,registry 上的 1.6.1 == latest,没有新版可拉。
|
||
# ⚠️ 这个 tag 不在任何 registry 上:本机 docker/judge/build.sh 构建,
|
||
# 服务器/机房用 docker load 装。镜像不在本地时 compose 会去 pull 然后报找不到。
|
||
image: oj2-judge-2
|
||
container_name: oj-judge
|
||
restart: always
|
||
read_only: true
|
||
cap_drop:
|
||
- SETPCAP
|
||
- MKNOD
|
||
- NET_BIND_SERVICE
|
||
- SYS_CHROOT
|
||
- SETFCAP
|
||
- FSETID
|
||
tmpfs:
|
||
- /tmp
|
||
volumes:
|
||
- ${DATA_DIR:-../data}/backend/test_case:/test_case:ro
|
||
# 判题机的运行状态目录。默认跟着 DATA_DIR 走,和旧栈是同一份 ——
|
||
# 一次性切换时无所谓(旧判题机已经停了),但**并行试跑时必须单独设 JUDGE_STATE_DIR**,
|
||
# 否则新旧两个 judger 同时往一个 run/log 目录里写。
|
||
- ${JUDGE_STATE_DIR:-${DATA_DIR:-../data}/judge_server}/log:/log
|
||
- ${JUDGE_STATE_DIR:-${DATA_DIR:-../data}/judge_server}/run:/judger
|
||
environment:
|
||
SERVICE_URL: http://oj-judge:8080
|
||
# 心跳路径跟着新后端改了:judge_server_heartbeat/ → judge-server/heartbeat
|
||
BACKEND_URL: http://oj-api:3000/api/judge-server/heartbeat
|
||
TOKEN: ${OJ2_JUDGE_TOKEN:?请在 docker/.env 里设置 OJ2_JUDGE_TOKEN}
|
||
# 同一时刻最多六份在编译(正式判题 2、试运行 2、提交前编译检查 2),g++ 编一份 iostream
|
||
# 峰值约 70MB、bits/stdc++.h 约 195MB,再加学生程序本身。512m 不够撑满,超了是容器里
|
||
# 随机杀进程、学生看到系统错误
|
||
mem_limit: 1g
|
||
|
||
oj-api:
|
||
build: &build
|
||
context: ..
|
||
dockerfile: docker/Dockerfile
|
||
target: api
|
||
# 产物来源,见 docker/Dockerfile 顶部。默认 build(服务器自己编);
|
||
# CI 传 ARTIFACTS=prebuilt 用 runner 编好的产物。
|
||
args:
|
||
ARTIFACTS: ${ARTIFACTS:-build}
|
||
image: oj2-api:latest
|
||
container_name: oj-api
|
||
restart: always
|
||
depends_on:
|
||
oj-postgres:
|
||
condition: service_healthy
|
||
oj-redis:
|
||
condition: service_healthy
|
||
volumes:
|
||
- ${DATA_DIR:-../data}/backend:/data
|
||
environment: &api-env
|
||
DATABASE_URL: postgres://onlinejudge:${POSTGRES_PASSWORD:?}@oj-postgres:5432/onlinejudge
|
||
# 密码拼进 URL,所以只能用 URL 安全的字符 —— 用 openssl rand -hex 32 生成
|
||
REDIS_URL: redis://:${REDIS_PASSWORD:?请在 docker/.env 里设置 REDIS_PASSWORD}@oj-redis:6379
|
||
JUDGE_SERVER_URL: http://oj-judge:8080
|
||
JUDGE_SERVER_TOKEN: ${OJ2_JUDGE_TOKEN:?}
|
||
JUDGE_CONCURRENCY: ${JUDGE_CONCURRENCY:-2}
|
||
TRIAL_CONCURRENCY: ${TRIAL_CONCURRENCY:-2}
|
||
AI_KEY: ${AI_KEY:-}
|
||
AI_HINT_DIAGNOSE: ${AI_HINT_DIAGNOSE:-}
|
||
healthcheck:
|
||
test: ["CMD", "oj2-api", "healthcheck"]
|
||
interval: 30s
|
||
timeout: 3s
|
||
retries: 3
|
||
start_period: 10s
|
||
mem_limit: 512m
|
||
# 理由同 oj-postgres:上课时学生翻页、看结果要先于判题拿到 CPU
|
||
cpu_shares: 2048
|
||
|
||
oj-worker:
|
||
build: *build
|
||
image: oj2-api:latest
|
||
container_name: oj-worker
|
||
restart: always
|
||
depends_on:
|
||
- oj-api
|
||
volumes:
|
||
- ${DATA_DIR:-../data}/backend:/data
|
||
environment: *api-env
|
||
# 同一个镜像,换个子命令就是判题消费者
|
||
command: ["oj2-api", "worker"]
|
||
# SQL 判题的子进程各允许 512MB 数据段(judge/sql 的 ulimit -d),两个并发就能顶满 512m
|
||
mem_limit: 1g
|
||
|
||
oj-web:
|
||
build:
|
||
context: ..
|
||
dockerfile: docker/Dockerfile
|
||
target: web
|
||
args:
|
||
ARTIFACTS: ${ARTIFACTS:-build}
|
||
image: oj2-web:latest
|
||
container_name: oj-web
|
||
restart: always
|
||
depends_on:
|
||
- oj-api
|
||
volumes:
|
||
# Caddy 只往这里写访问日志,静态资源在镜像里
|
||
- ${DATA_DIR:-../data}/backend/log:/data/log
|
||
ports:
|
||
# 并行试跑(oj2.xuyue.cc)时换一个端口,8080 还被旧 backend 占着。
|
||
- "0.0.0.0:${WEB_PORT:-8080}:8000"
|
||
mem_limit: 256m
|