Domjudge 8.3 Docker 无痛配置
Domjudge 8.3
基于Debian, docker 安装
前置说明
先把docker安装好,然后因为举办该比赛没有用选手机,所以并没有学习选手机如何配置,同时由于设备和规模问题,气球小票机也没有配置,后面有机会再学习了
参考博客Domjudge配置指南 & 校赛踩坑记录 - 知乎
数据库
从docker上pull 数据库的镜像
docker pull dockerpull.org/mariadb
先安装数据库使用mysql
docker run --restart=always -d -it --name dj-mariadb \
-e MYSQL_ROOT_PASSWORD=%1% \
-e MYSQL_USER=domjudge \
-e CONTAINER_TIMEZONE=Asia/Shanghai \
-e MYSQL_PASSWORD=%2% \
-e MYSQL_DATABASE=domjudge -p %3%:3306 \
dockerpull.org/mariadb --max-connections=1000 --max-allowed-packet=2048000000 --innodb-log-file-size=20480000000
命令中%%部分需要替换成实际值
MYSQL_ROOT_PASSWORD是数据库的root密码建议修改
MYSQL_PASSWORD是数据库的密码建议修改
--max-connections为最大连接数
--max-allowed-packet为你最大测试点大约2倍的值单位B
--innodb-log-file-size为你最大测试点大约10倍的值单位B
映射数据库 /home/Domjudge/db/mysql 修改为本地文件夹
#如果之前没创建过,就不用输这个命令
rm -rf /home/Domjudge/db/mysql
#将数据库的文件夹复制到本地
docker cp dj-mariadb:/etc/mysql /home/Domjudge/db/mysql
然后删除容器
#删除容器
docker rm -f dj-mariadb
#删除容器的卷,之前因为没删除卷导致硬盘一下就满了
docker volume prune
然后重新安装容器
docker run --restart=always -d -it --name dj-mariadb \
-e MYSQL_ROOT_PASSWORD=%1% \
-e MYSQL_USER=domjudge \
-e CONTAINER_TIMEZONE=Asia/Shanghai \
-e MYSQL_PASSWORD=%2% \
-e MYSQL_DATABASE=domjudge -p %3%:3306 \
-v /home/Domjudge/db/mysql:/etc/mysql \
dockerpull.org/mariadb --max-connections=1000 --max-allowed-packet=2048000000 --innodb-log-file-size=20480000000
下面的命令,在配置过程中可能会用到
#删除所有卷
docker volume prune
#删除所有容器
docker rm -f $(docker ps -aq)
domserver
拉镜像
docker pull dockerpull.org/domjudge/domserver:8.3.1
创建domserver容器
docker run --restart=always --link dj-mariadb:mariadb -d -it \
-e MYSQL_HOST=mariadb \
-e MYSQL_USER=domjudge \
-e MYSQL_DATABASE=domjudge \
-e CONTAINER_TIMEZONE=Asia/Shanghai \
-e MYSQL_PASSWORD=<数据库的密码> \
-e MYSQL_ROOT_PASSWORD=<数据库root的密码> \
-p <根据需要映射端口>:80 --name domserver dockerpull.org/domjudge/domserver:8.3.1
Domjudge后台管理员的初始密码
docker exec -it domserver cat /opt/domjudge/domserver/etc/initial_admin_password.secret
用这个密码可以用,admin登录web,进入管理员界面
Domjudge的API KEY,配置judgehost需要
docker exec -it domserver cat /opt/domjudge/domserver/etc/restapi.secret
输出大概长这样
Randomly generated on host , Sat Dec 7 17:38:09 CST 2024
Format: '<ID> <API url> <user> <password>'
default http://localhost//api judgehost APIKEY
这里就已经可以登录到web端查看了
judgehost
拉镜像
docker pull dockerpull.org/domjudge/judgehost:8.3.1
修改cgroub,文件在/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1"
#如果你核够用,可以考虑开启守护进程
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1 isolcpus=2"
#如果你的cgrub版本比较低,或者出现其他的问题,导致容器一直再重启,可以考虑用下面的这句
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1 isolcpus=2 systemd.unified_cgroup_hierarchy=0"
然后执行
update-grub
reboot
创建judgehost容器
#这里我们创建四个judgehost, 将JUDGEDAEMON_PASSWORD替换成上面查看的APIKEY
docker run -d --restart=always -it --privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
--name judgehost-0 \
--link domserver:domserver \
--hostname judgedaemon-0 \
-e DAEMON_ID=0 \
-e JUDGEDAEMON_PASSWORD=APIKEY \
-e CONTAINER_TIMEZONE=Asia/Chendu \
dockerpull.org/domjudge/judgehost:8.3.1
docker run -d --restart=always -it --privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
--name judgehost-1 \
--link domserver:domserver \
--hostname judgedaemon-1 \
-e DAEMON_ID=1 \
-e JUDGEDAEMON_PASSWORD=APIKEY \
-e CONTAINER_TIMEZONE=Asia/Chendu \
dockerpull.org/domjudge/judgehost:8.3.1
docker run -d --restart=always -it --privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
--name judgehost-2 \
--link domserver:domserver \
--hostname judgedaemon-2 \
-e DAEMON_ID=2 \
-e JUDGEDAEMON_PASSWORD=APIKEY \
-e CONTAINER_TIMEZONE=Asia/Chendu \
dockerpull.org/domjudge/judgehost:8.3.1
docker run -d --restart=always -it --privileged \
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
--name judgehost-3 \
--link domserver:domserver \
--hostname judgedaemon-3 \
-e DAEMON_ID=3 \
-e JUDGEDAEMON_PASSWORD=APIKEY \
-e CONTAINER_TIMEZONE=Asia/Chendu \
dockerpull.org/domjudge/judgehost:8.3.1
通过命令进入容器
docker exec -it <Id> /bin/bash
# docker exec -it judgehost-0 /bin/bash
进入chroot
chroot /chroot/domjudge/
通过cat的方式换源
cat > /etc/apt/sources.list << 'EOF'
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free non-free-firmware
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware
EOF
更新源
apt update
安装py, java, g++, gcc环境
#java安装需要挂载
mount -t proc none /proc
mkdir -p /usr/share/man/man1
apt-get install -y gcc g++ python3 openjdk-17-jdk
查看环境配置
python3 --version;java -version;gcc --version;g++ --version
导入团队和账户
先准备teams.json和accounts.json两个文件
如果用json导入,先把Configuration settings中的External systems中的Data source修改为configuration data external
teams.json比如
[{
"id": "100", // 队伍唯一id
"name": "我是A队", // 队伍名字
"display_name": "我是A队", // 榜单显示名字
"icpc_id": "formal_100", // 队伍外部id
"label": "1", // 标签, 座位什么的,需要唯一
"members": "A B C", // 成员
"group_ids": ["participants"], // 队伍类型 对应Team Categories 中的external ID
"organization_id": "school" // 学校 对应Team Affiliations中的external ID
}, {
"id": "101",
"name": "我是B队",
"display_name": "我是B队",
"icpc_id": "formal_101",
"label": "2",
"members": "A B C",
"group_ids": ["participants"],
"organization_id": "school"
}
]
accounts.json
[{
"id": "formal-100", //账户唯一id
"username": "formal-100", //用户名,唯一
"password": "",// 密码
"team_id": "100",// 与teams中id对应, 表示该账户是 id队伍的
"type": "team", // 类型 team就行
"name": "A" // 名字, 该用户的名字
}, {
"id": "formal-101",
"username": "formal-101",
"password": "",
"team_id": "101",
"type": "team",
"name": "B"
}
]
如果配置了organization_id,需要保证teams.json中的所有organization_id对应的值已经在存在,可以在web上的Team Affiliations配置里面看到,然后再上传teams.json,再上传accounts.json
创建一场比赛
导入contest.json
{
"id": "formal_contest",
"formal_name": "formal_contest",
"name": "正式赛",
//时间采用绝对时间格式
"start_time": "2024-12-08T12:00:00+08:00",
"duration": "5:00:00",
"penalty_time": 20,
"activate_time": "2024-12-08T12:00:00+08:00",
"medals": {
"gold": 20,
"silver": 40,
"bronze": 60
},
"scoreboard_freeze_duration": "01:00:00"
}
导入题目
采用以下格式
│ domjudge-problem.ini
│ problem.pdf
│ problem.yaml
│
└─data
└─sample
1.ans
1.in
2.ans
2.in
└─secret
3.ans
3.in
4.ans
4.in
problem.yaml大概长这样
limits:
memory: 256
name: 起床别睡啦
domjudge-problem.ini大概长这样
short-name = A
timelimit = 1.0
color = #000000
externalid = a0005
最后打包成.zip文件就行
如果上传失败可以考虑检查数据库的配置是否合理,再看看config cheker是不是有问题
当然如果不知道怎么配置,可以考虑在polygon上出好题后用p2d工具转换
Polygon2DOMjudge/README.cn.md at master · cn-xcpc-tools/Polygon2DOMjudge
导出提交文件
使用这个工具LaiJunBin/domjudge-code-download-tool: Download domjudge contest source code tool.
但是存在一些bug,我已经修改了,给原作者反馈问题了
可以下载我修改好的包
然后运行的话,建议在wsl上运行,实测没有出过问题,在Pycharm和windows上都出过大大小小的bug
导出计分板
可以直接在web后台的contest里面导出
ICPC Tool
The ICPC Tools | Home所有工具的链接,最好下载最新的,而不是下载稳定版本
我是运行在Windows上的,其他操作系统未知.
Contest Data Server
参考博客
关于搭建 domjudge 还有其他一些 ICPC Tool 之类的事 – 赤红幻想
Connecting the ICPC Tools with DOMjudge · DOMjudge/domjudge Wiki
本地配置
CDS 又叫 Contest Data Server,主要用以比赛后台的一些管理服务,得先配置好这个才能用其他 Tools(Resolver 除外)。
然后进入到wlp/usr/servers/cds/config/cdsConfig.xml,将文件内容直接全部修改为
<cds>
<!-- Set location= to a directory that the user running the CDS can write to -->
<contest location="/home/cds/contest-data" recordReactions="false">
<!-- Set the url to the URL of your DOMjudge installation, followed by /api/contests/<cid>, where <cid> is your CID or external ID -->
<!-- Set the user and password to the user you created in the previous step -->
<ccs
url="http://www.domjudge.org/demoweb/api/contests/nwerc18"
user="cds"
password="somepassword" />
</contest>
</cds>
然后修改location为一个用户可以修改的文件目录
然后url 为比赛的api链接,如果你设置了external data source,这里的cid为external ID
http://{ip}//api/v4/contests/{cid}
user和password分别对应usercds 和 usercdspwd, 管理员账号也可以
然后配置accounts.yaml
里面的username 和 type都不要修改,password建议修改,为了安全
接下来就可以运行(需要装 java jdk 11 或以上)
wlp/bin/server run cds
来启动 CDS 了,关闭的话直接 Ctrl+C 停止服务即可。
然后可以通过server ip为 你本地的任意ip
https://<server ip>:8443/
启动后可以看到以下界面

右上角可以用刚才accounts.yaml文件中的admin用户登录
docker配置
先pull镜像
docker pull ghcr.io/icpctools/cds:2.6.1166
如果你拉取不下来,这里有我已经下载好的cds_docker
docker load -i cds.tar.gz
然后创建容器
docker run --name cds --rm -d -p 8080:8080 -p 8443:8443 -e CCS_URL=http://<ip:post>/api/v4/contests/<cid> -e CCS_USER=admin -e CCS_PASSWORD=<passwd> ghcr.io/icpctools/cds:2.6.1166
这里的ccs_url建议用http,其中
ccs_user需要API reader的角色,和Source code reader
然后进入到cds容器里面
docker exec -it cds /bin/bash
cat /opt/wlp/usr/servers/cds/config/cdsConfig.xml
其配置文件路径为:/opt/wlp/usr/servers/cds/config/cdsConfig.xml
Presentation Admin
这是个屏幕显示后台管理工具,可以管理多个 Client 的屏幕显示。
然后在bash里面运行这个命令
cdsurl为刚才启动的cds页面, user为accounts.yaml中的presAdmin,password同理
presAdmin.bat/sh cdsURL user password [options]
./presAdmin.bat <cdsurl> <user> <password>
只要出现这个页面,那么就启动成功了

Presentation Client
用于管理屏幕的
用下面的命令启动即可
./client.bat https://<server ip>:8443/api/contests/<cid> presentation <presentation password> --name <client name>
由于可能存在中文乱码的问题
所以这里有一种解决方式
进入到C:\Windows\Fonts后选择一款字体,然后放到lib/presentations.jar/font
presentations.jar可以用7z或者其他解压工具打开
替换掉原来的字体Helvetica-Plain.ttf
Resolver(滚榜)
awards.bat
有两种方式

RESK是通过CDS地址来拉取,Disk是通过event-feed.json来拉取数据的,
event-feed.json通过下面的链接下载
https://<domjudge url>/api/v4/contests/<cid>/event-feed?stream=false

如果出现这种情况也无所谓,只要能拉到表就行
然后点击Operations下的save event feed.ndjson然后会保存一个event feed.ndjson
#通过cds的链接来启动
.\resolver.bat <cds> admin <passwd> [options]
#通过cdp目录启动,建议这个
.\resolver.bat <contestPackagePath> [options]
#通过eventfeed文件来启动
.\resolver.bat <eventFeedPath> [options]
什么是cdp目录Contest Package Format · CCS Specs
这个目录也很好获取
首先你在本地配置cds后,他会在location你配置的location位置下生成一些下面需要的东西
<contest location="/home/cds/contest-data" recordReactions="false">
在自己添加一个config文件夹就可以了,然后把award生成的event-feed.ndjson放到这里就行
.
├── config // 非必需
│ ├── contest.yaml // 从domjudge Import/export页面导出即可
│ ├── groups.tsv // 从domjudge Import/export页面导出即可
│ ├── problemset.yaml
│ └── teams.tsv // 从domjudge Import/export页面导出即可
├── contest
│ ├── banner.png // resolver无用,但在cds放置于此就可显示banner
│ └── logo.png // resolver主页面的图片&无照片队伍的默认照片
├── event-feed.ndjson // 滚榜数据
├── groups // Categories照片,但在resolver似乎没起到作用
│ └── 3 // Categories的id
│ └── logo.png
├── organizations // Affiliations照片,只要某Affiliations的队伍有logo,其他同Affiliations的队伍就都是该logo
│ ├── 3000 // 该Affiliations所对应的任一队伍的icpc id
│ │ └── logo.png
│ ├── 3001
│ │ └── logo.png
│ ├── 3012
│ │ └── logo.png
│ ├── 3017
│ │ ├── country_flag.png // 照源码里是这样放置的,但在resolver似乎没起到作用
│ │ └── logo.png
│ └── 3187
│ └── logo.png
└── teams // 队伍照片
├── 3000 // 队伍的icpc id
│ └── photo.png // 照片名字固定是photo
├── 3001
│ └── photo.png
├── 3009
│ └── photo.png
└── 3010
└── photo.png
然后就可以直接
.\resolver.bat cpd路径 --singleStep 999
--pause
--speed
--light 主题改为light
--display
--singleStep
相关操作
Ctrl-Q 退出
space 或者 f 前进一步
r 或者 b 退后一步
0 重新开始
2 快进一步(没有延迟)
1快退一步(没有延迟)
+ 或者 =加快解析速度
- 或者 _降低解析速度
其他问题
如何在颁奖界面显示队伍名字
两种方式
第一种,我们给每个队伍有奖的队伍放一张他们的图片,图片放在teams下面
第二种,我们给每个队伍颁一个奖,奖项的名字叫他们团队的名字

在award里面是这样写的
我们可以写写脚本生成,直接对应event-feed.ndjson里面
//格式
{
"type":"awards", //事件类型 这里写奖项
"id":"id_formal_contest_100", //奖项id
"data":{
"id":"id_formal_contest_100", //奖项id
"team_ids":["formal_contest_100"],// 获奖的队伍id
"citation":"队伍名称", //屏幕上显示什么
"display_mode":"pause", //滚榜模式
"parameters":{}
},
"token":"cd233722" // 事件id 一般接着上面的写连续就行
}
{"type":"awards","id":"observer-bronze-medal","data":{"id":"observer-bronze-medal","team_ids":["formal_contest_337","formal_contest_373"],"citation":"等同铜奖","parameters":{}},"token":"cd233721"}
{"type":"awards","id":"id_formal_contest_100","data":{"id":"id_formal_contest_100","team_ids":["formal_contest_100"],"citation":"我是名字","display_mode":"pause","parameters":{}},"token":"cd233722"}
两个注意点,type对应的字段是awards,id需要唯一,如果是给队伍显示名字,"display_mode":"pause"需要加上这个字段,然后token需要和上面的连续team_ids是一个数组,包含哪些队伍获得该奖项citation是奖项名字
在榜单显示学校logo
在Configuration settings中Display中关掉Show flags打开Show affiliation logos
logo获取可以取这个网站看看555所大学校徽 - 中国大学矢量校徽大全
参考
关于搭建 domjudge 还有其他一些 ICPC Tool 之类的事 – 赤红幻想
Polygon2DOMjudge/README.cn.md at master · cn-xcpc-tools/Polygon2DOMjudge
Connecting the ICPC Tools with DOMjudge · DOMjudge/domjudge Wiki
Connecting the ICPC Tools with DOMjudge · DOMjudge/domjudge Wiki
Contest Package Format · CCS Specs
cn-xcpc-docs/domserver.md at master · cn-xcpc-tools/cn-xcpc-docs

浙公网安备 33010602011771号