Files
OJ2/docker/compose.debian.yml
T
xuyueandClaude Opus 5.5 6176b80ad9
Deploy / deploy (push) Canceled after 0s
chore(部署): 服务器的 judge0 早就删了,注释里还写着它
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 15:05:49 +08:00

184 lines
7.5 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 服务器(oj.xuyue.cc)。数据库在这里,机房那套连的就是这里的 5445。
#
# docker/deploy.sh # 平时走这个(自检 → 构建 → 迁移 → 起栈 → 冒烟)
#
# 构建上下文是仓库根,所以 build.context 写 ..(相对本文件)。
#
# **服务器上的全部容器都由这一个文件起**,包括 postgres 和 redis。以前库和 redis 是旧栈
# 那份 /root/OJDeploy/docker-compose.yml 起的、这里通过 DB_HOST 外接过去,2026-10 起收了进来。
#
# ⚠️ `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、另一套 go-judge 等二十多个别的服务挤在一起(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:
# 自己构建的判题沙箱(go-judge + gcc / python,见 docker/judge/)。
# ⚠️ 这个 tag 不在任何 registry 上:本机 docker/judge/build.sh 构建,
# 服务器/机房用 docker load 装。镜像不在本地时 compose 会去 pull 然后报找不到。
image: oj2-judge-3
container_name: oj-judge
restart: always
# go-judge 要自己建 namespace 和 cgroup 来关学生程序,只能给特权,理由见 docker/judge/README.md
privileged: true
# go-judge 的文件存储(编译产物、程序输出)放这里,见 docker/judge/Dockerfile 的 -dir
tmpfs:
- /tmp
volumes:
- ${DATA_DIR:-../data}/backend/test_case:/test_case:ro
environment:
ES_AUTH_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:?}
# 后台「判题机列表」里这一台的名字(worker 替判题机记心跳,见 judge/heartbeat.ts)
JUDGE_SERVER_NAME: 服务器
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:
- "0.0.0.0:${WEB_PORT:-8080}:8000"
mem_limit: 256m