别再到处找OJ平台了!手把手教你用Docker在Ubuntu上部署QDUOJ(附端口避坑指南)
私有化在线判题系统实战:基于Docker的QDUOJ高效部署指南
在算法竞赛训练和编程教学中,公共在线判题系统(OJ)往往面临题目类型受限、网络延迟高、数据隐私无法保障等痛点。本文将带你从零开始,在Ubuntu服务器上通过Docker快速部署QDUOJ系统,打造专属的私有化评测环境。不同于简单的步骤罗列,我们将深入探讨容器化部署的最佳实践,并分享实际运营中的经验技巧。
1. 环境准备与核心组件解析
1.1 服务器基础配置
选择Ubuntu 20.04 LTS作为基础系统,这是目前最稳定的长期支持版本。在开始前,建议执行以下基础环境检查:
# 检查系统版本
lsb_release -a
# 更新软件源
sudo apt update && sudo apt upgrade -y
关键组件依赖关系:
| 组件 | 作用 | 推荐版本 |
|---|---|---|
| Docker | 容器运行时环境 | 20.10+ |
| docker-compose | 多容器编排工具 | 1.29+ |
| Python3 | 脚本支持环境 | 3.6+ |
| Git | 代码版本管理 | 2.25+ |
提示:生产环境建议使用独立磁盘分区存放Docker数据,避免系统盘空间耗尽导致服务异常。
1.2 Docker引擎优化配置
国内用户推荐使用阿里云镜像加速安装:
# 安装必要工具
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
# 添加Docker官方GPG密钥
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# 设置稳定版仓库
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# 安装Docker引擎
sudo apt install -y docker-ce docker-ce-cli containerd.io
配置Docker守护进程参数:
# 创建配置文件目录
sudo mkdir -p /etc/docker
# 配置镜像加速和日志限制
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://your-aliyun-mirror.mirror.aliyuncs.com"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
EOF
# 重启服务生效
sudo systemctl daemon-reload
sudo systemctl restart docker
2. QDUOJ容器化部署实战
2.1 项目结构与部署流程
获取官方部署模板:
git clone -b 2.0 https://github.com/QingdaoU/OnlineJudgeDeploy.git
cd OnlineJudgeDeploy
目录结构关键说明:
OnlineJudgeDeploy/
├── docker-compose.yml # 多容器编排定义
├── data/ # 持久化数据存储
│ ├── mysql/ # 数据库文件
│ └── redis/ # 缓存数据
└── config/ # 应用配置文件
端口规划建议:
| 服务 | 默认端口 | 安全建议 |
|---|---|---|
| Web前端 | 80/443 | 建议改为非标准端口如8080 |
| MySQL | 3306 | 限制仅本地访问 |
| Redis | 6379 | 设置密码认证 |
修改docker-compose.yml中的端口映射:
services:
oj-web:
ports:
- "8080:80" # 将80改为8080
2.2 一键启动与健康检查
启动所有服务:
docker-compose up -d
监控启动日志:
# 查看实时日志
docker-compose logs -f
# 检查容器状态
watch -n 2 docker-compose ps
健康状态验证:
# 检查各容器运行状态
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
注意:首次启动可能需要5-30分钟完成初始化,具体取决于网络速度和服务器性能。
3. 系统安全加固与基础配置
3.1 关键安全措施
-
修改默认凭证:
- 登录后台
http://服务器IP:8080/admin - 立即修改root账户密码(默认rootroot)
- 创建具有适当权限的次级管理员账户
- 登录后台
-
网络访问控制:
# 仅允许特定IP访问管理后台 sudo ufw allow from 你的IP to any port 8080 sudo ufw enable -
数据库安全加固:
# 进入MySQL容器 docker exec -it oj-mysql mysql -uroot -p执行SQL命令修改root密码并创建专用账户:
ALTER USER 'root'@'%' IDENTIFIED BY '新复杂密码'; CREATE USER 'oj_user'@'%' IDENTIFIED BY '专用密码'; GRANT ALL PRIVILEGES ON onlinejudge.* TO 'oj_user'@'%'; FLUSH PRIVILEGES;
3.2 性能调优建议
调整Redis配置:
docker exec -it oj-redis redis-cli
CONFIG SET maxmemory 1gb
CONFIG SET maxmemory-policy allkeys-lru
MySQL性能参数优化(在docker-compose.yml中添加):
oj-mysql:
environment:
- MYSQL_INNODB_BUFFER_POOL_SIZE=1G
- MYSQL_INNODB_LOG_FILE_SIZE=256M
4. 题目管理与系统运维
4.1 题目导入规范
标准题目包结构示例:
problem_1001/
├── testcase/
│ ├── 1.in
│ ├── 1.out
│ ├── 2.in
│ └── 2.out
└── problem.md
题目元数据配置要点:
- 时间限制单位:毫秒(1000ms=1s)
- 内存限制单位:MB(通常设置64-1024MB)
- 评测模式选择:
- ACM模式:实时返回结果
- OI模式:比赛结束后统一评测
4.2 日常维护命令
备份数据库:
docker exec oj-mysql sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" onlinejudge' > oj_backup_$(date +%Y%m%d).sql
日志轮转设置:
# 设置日志文件大小限制
docker-compose exec oj-web bash -c "ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log"
系统升级流程:
# 停止旧服务
docker-compose down
# 拉取最新代码
git pull origin 2.0
# 重新构建镜像
docker-compose build --no-cache
# 启动新服务
docker-compose up -d
5. 高级功能扩展
5.1 多节点分布式部署
修改docker-compose.yml实现负载均衡:
oj-judge:
deploy:
mode: replicated
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
5.2 集成持续评测系统
通过Webhook实现Git仓库自动评测:
# 示例:GitLab Webhook处理器
@app.route('/webhook', methods=['POST'])
def handle_webhook():
data = request.json
if data['object_kind'] == 'push':
clone_repo(data['repository']['git_ssh_url'])
run_test_cases()
return jsonify({'status': 'processing'})
5.3 自定义评测器开发
创建特殊判题程序(SPJ):
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char* argv[]) {
ifstream user_out(argv[1]); // 用户输出
ifstream std_out(argv[2]); // 标准输出
// 自定义比对逻辑
double a, b;
user_out >> a;
std_out >> b;
if(fabs(a - b) < 1e-6) {
return 0; // AC
} else {
return 1; // WA
}
}
部署到服务器指定目录:
docker cp spj oj-web:/usr/local/bin/
docker exec oj-web chmod +x /usr/local/bin/spj
在实际运营中,我们发现合理设置题目难度梯度对用户体验至关重要。初期建议准备20-30道涵盖不同难度级别的题目,从简单的"Hello World"输出题到中等难度的算法题逐步过渡。定期查看系统日志分析用户提交模式,可以优化题目设置和服务器资源配置。
更多推荐
所有评论(0)