
用 Linux 虚拟机部署 Hydro 这套流程我前后完整走过七八遍从最早拿一台四年前的旧笔记本跑 VMware到后来在服务器上开 KVM 做正式的校内选拔赛中间踩的坑几乎能凑成一本小册子。Hydro 是一套开源的在线评测系统用 Node.js 加 MongoDB 搭起来能自动判题、组织比赛、管理题库、排训练计划做校内算法训练或者团队内部刷题都很合适。而先开一台 Linux 虚拟机再装这个做法本质上是为了给自己留一条退路装崩了直接回滚快照不用重装系统也不用担心把日常工作机搞乱。这篇内容写给两类人——一类是完全没碰过虚拟机的同学照着做也能跑通另一类是已经在物理机上装过一次、结果被依赖问题折腾到怀疑人生的朋友这篇里的排查链路应该能帮你省掉不少时间。下面所有的命令和参数都是我在 Ubuntu 22.04 和 Debian 12 上实测过的路径和版本号会随发行版变化遇到对不上的地方以你本机--help的输出为准。1. 开工前先想清楚Hydro 到底要吃多少资源1.1 Hydro 的组成决定了它的资源胃口很多人对在线评测系统的第一印象是不就是个网站吗1 核 1G 随便跑。真按这个规格开虚拟机大概率会在编译前端资源那一步卡死或者跑起来之后每隔十分钟被 OOM Killer 干掉一次。原因在于 Hydro 不是单体应用它至少由三块东西拼成Web 服务进程本身Node.js负责页面渲染、接口、任务调度、MongoDB存题目、提交记录、用户数据、比赛信息、以及评测沙箱真正执行用户代码、限制时间和内存的那部分。这三块对资源的需求完全不一样。MongoDB 的 WiredTiger 存储引擎默认会申请大约物理内存减去 1GB 再除以 2作为缓存也就是说你给虚拟机 4GB 内存它一上来就想占掉 1.5GB 左右Node.js 主进程在空闲时大概 200 到 400MB但如果同时在编译前端资源或者处理多个提交冲到 1GB 也不奇怪评测沙箱每跑一个测试点评测都会 fork 出独立进程并施加资源限制虽然单个进程被限制得很小但并发评测时是叠加的。把这三块加在一起再留出操作系统自身和文件缓存的空间就能倒推出配置单了。我一般按下表来开机器实测下来余量比较舒服使用场景vCPU内存磁盘备注个人学习 / 跑通流程24GB40GB编译慢但能跑起来小团队内部训练几十人48GB60GB我推荐的起步配置正式比赛百人以上816GB 起100GB SSD建议把评测拆到独立机器磁盘这一项特别提醒一句虚拟机磁盘别用动态分配的精简置备跑正式用途。表面上看 40GB 的虚拟磁盘只占了宿主机 15GB很省地方但比赛期间提交记录和测试数据增长很快磁盘写满之后 MongoDB 会直接拒绝写入那时候想扩容还得关机、改配置、再开机比赛正在进行的话就非常被动。1.2 系统版本选哪个别选太新的也别选太老的Hydro 的部署脚本和官方文档主要以 Debian 系为基础所以选系统的时候没必要给自己加难度。下面是我试过或者身边人试过的几种情况系统部署顺畅度说明Ubuntu 22.04 LTS很顺官方脚本基本是为它写的资料最多Ubuntu 24.04 LTS较顺Node 和 Mongo 源需要确认是否已支持Debian 12很顺更干净占资源更少Rocky / AlmaLinux 9一般SELinux 会拦住端口和文件访问要多配一步Kali不推荐预装了大量安全工具依赖冲突概率高Kali 单独说一句热搜里经常有人问能不能用 Kali 学这套东西。Kali 本质上也是 Debian理论上是能装的但它的软件源里塞了一堆渗透测试工具某些库的版本跟 MongoDB 或者 Node 官方源会打架我之前在 Kali 上装到一半碰到libssl版本冲突换 Debian 之后同样的命令一次过。学习环境就别给自己找麻烦了。1.3 创建虚拟机时那几个容易被忽略的开关这部分是纯经验书上通常不写但出问题的时候特别让人抓狂。第一宿主机 BIOS 里的虚拟化开关必须打开。Intel 平台叫 VT-xAMD 平台叫 SVM名字不一样位置通常在 Advanced 或者 CPU Configuration 里面。这个开关没开虚拟机要么起不来要么装系统过程中直接蓝屏。热搜里虚拟机安装linux蓝屏这个搜索词我估计八成的人栽在这里。判断方法很简单在任务管理器或者 CPU-Z 里看有没有虚拟化已启用没有就去 BIOS 里开。第二虚拟机软件里那个虚拟化引擎的选项要勾上。VMware 的路径是虚拟机设置 → 处理器 → 虚拟化引擎里面有两个复选框。如果你打算在虚拟机里面再跑 Docker 或者容器化的评测环境这两个必须勾。不勾的话虚拟机内部会报这台主机不支持硬件虚拟化。第三别用简易安装。用 VMware 新建虚拟机的时候它会检测到你选了 Ubuntu 的 ISO 就自动走简易安装流程帮你把用户名密码都设好了看起来省事实际上会跳过分区和软件包选择装出来的系统经常缺一些基础组件后面apt各种报错。正确做法是在向导里明确选稍后安装操作系统把虚拟机建好之后再把 ISO 挂上去手动装。第四虚拟机目录如果建在机械硬盘或者外接移动硬盘上编译前端资源那一步会慢到你想砸键盘。Hydro 的依赖安装加上前端构建在 SSD 上大概五到十分钟在机械盘上可能要半小时以上还容易超时中断。2. 网络配置让宿主机和局域网都能打开 Hydro 页面2.1 NAT 和桥接的本质区别以及为什么我倾向桥接虚拟机网络这块最让人迷糊的就是 NAT 和桥接到底选哪个。用一个类比解释NAT 模式相当于虚拟机住在宿主机家里对外的一切通信都要宿主机帮忙转达外部的人根本不知道虚拟机这个家庭成员的存在桥接模式相当于虚拟机直接在小区里分了一套房有自己的门牌号邻居局域网里的其他设备可以直接敲门。具体到装 Hydro 这件事上区别是这样的只用宿主机访问NAT 就够了宿主机的浏览器直接敲虚拟机 IP 就能打开页面。要让同学用手机或者自己的电脑访问必须桥接或者手动在 NAT 里做端口映射。要做比赛让外网也能访问桥接之后配合路由器端口映射或者干脆部署到有公网 IP 的机器上。我踩过的一个坑是VMware 在 NAT 模式下虚拟机的 IP 段通常是 192.168.X.0/24而宿主机上的其他虚拟网卡比如 Docker 的默认网桥、某些远程办公软件创建的虚拟网卡很可能占用了同样的网段结果就是宿主机能 ping 通虚拟机但浏览器死活打不开页面。这种问题排查起来特别费劲因为看着都正常。后来我的做法就是把虚拟机网络统一改成桥接IP 段由家里的路由器分配跟宿主机平级冲突概率低很多。如果实在不方便用桥接比如公司网络做了端口隔离那就老老实实用 NAT 加端口映射。VMware 的路径是编辑 → 虚拟网络编辑器 → 选中 VMnet8 → 右下角NAT 设置 → 添加一条映射宿主机端口填 8080虚拟机 IP 填你的虚拟机地址虚拟机端口填 80。这样在宿主机的浏览器里访问http://127.0.0.1:8080就等于访问虚拟机的 80 端口。2.2 给虚拟机配一个固定 IP别让它每次都换动态分配的 IP 在重启之后可能变每次都要去虚拟机里敲ip a看一眼麻烦且容易出错。建议在装完系统之后第一件事就把 IP 固定下来。Ubuntu 从 17.10 之后用 netplan 管网络配置文件在/etc/netplan/目录下通常是00-installer-config.yaml或者50-cloud-init.yaml。内容大概长这样network: version: 2 ethernets: ens33: dhcp4: no addresses: - 192.168.1.150/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: [223.5.5.5, 119.29.29.29]改完执行sudo netplan apply生效。这里有几个细节要注意网卡名字ens33必须换成你自己ip a看到的名字Ubuntu 桌面版可能是ens160或者enp0s3网关地址要跟你家路由器一致DNS 我用的是公共 DNS比走路由器转发在某些网络环境下响应快一点。如果netplan apply之后网络断了别慌直接在虚拟机控制台里改回来就行桌面版还可以用sudo dhclient ens33临时恢复。Debian 12 用的是/etc/network/interfaces写法更传统auto ens33 iface ens33 inet static address 192.168.1.150 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 223.5.5.5 119.29.29.29Rocky 或者 AlmaLinux 走的是 NetworkManager用nmcli改最省事sudo nmcli con mod ens33 ipv4.addresses 192.168.1.150/24 sudo nmcli con mod ens33 ipv4.gateway 192.168.1.1 sudo nmcli con mod ens33 ipv4.dns 223.5.5.5 119.29.29.29 sudo nmcli con mod ens33 ipv4.method manual sudo nmcli con up ens33配完之后从宿主机 ping 一下虚拟机地址通了再往下走。这一步不通后面所有关于页面的问题都免谈。2.3 宿主机打不开虚拟机网页的排查顺序这个场景太常见了我把排查顺序固化下来按顺序走一遍基本就能定位宿主机的命令行 ping 虚拟机 IP。不通说明是网络层问题回到 2.2 检查 IP、网关、防火墙。在虚拟机里curl -I http://127.0.0.1:8888。不通说明服务根本没起来去看服务日志。在虚拟机里ss -lntp | grep 8888。如果显示的监听地址是127.0.0.1:8888而不是0.0.0.0:8888那外部无论如何都访问不到。Hydro 默认只监听本地回环要通过--host 0.0.0.0或者配置文件放开。检查虚拟机自身的防火墙。Ubuntu 上是sudo ufw status如果状态是 active需要sudo ufw allow 8888/tcp。Rocky 上是sudo firewall-cmd --list-all用--add-port8888/tcp --permanent加规则再--reload。再在宿主机上curl -I http://虚拟机IP:8888。到这一步还不通基本就是虚拟网络模式的问题了回到 2.1 检查 NAT 或桥接设置。提示排查过程中不要同时在好几层动手改配置一次只动一个地方改完立刻验证。我见过有人在防火墙、监听地址、Nginx 配置三处同时改了最后虽然通了但完全不知道是哪一步起了作用下次遇到同样问题还是不会。3. Hydro 依赖三件套MongoDB、Node.js 和评测沙箱3.1 MongoDB 的版本选择和 AVX 指令集的坑Hydro 的数据全部存在 MongoDB 里题库、提交、比赛、用户、评分记录一个都跑不掉。所以 MongoDB 装不上后面全白搭。版本方面现在主流是 5.0、6.0、7.0 这几条线。这里有个特别隐蔽的坑MongoDB 从 5.0 开始编译时启用了 AVX 指令集优化如果你的 CPU 不支持 AVXmongod启动会直接崩掉日志里会出现Illegal instruction这一行。这个问题在物理机上很少见近十年的 CPU 基本都有 AVX但在虚拟机里出现的概率明显高一些——因为某些虚拟机软件的默认 CPU 兼容性设置会把 AVX 指令屏蔽掉或者你用的是很老的宿主机。判断方法是在虚拟机里执行grep -o avx /proc/cpuinfo | head -1有输出说明支持 AVX能装 5.0 以上没输出就只能退到 4.4 版本或者在虚拟机设置里把 CPU 的指令集透传打开VMware 在虚拟机设置的处理器选项里可以调整 CPU 掩码把 AVX 暴露给客户机。安装 MongoDB 官方源的步骤大致是导入 GPG 公钥、添加 apt 源、更新索引、安装mongodb-org。具体命令每个版本略有差别建议直接去 MongoDB 官方文档复制当前版本的安装命令别照抄博客里的老命令因为 GPG key 会轮换老 key 过期之后apt update会报签名验证失败。装完之后做两件事。第一件是确认服务状态sudo systemctl status mongod sudo systemctl enable mongod第二件是调一下缓存大小。前面说过 WiredTiger 默认要吃一半内存在只给 4GB 的虚拟机上太激进了。编辑/etc/mongod.conf加上storage: wiredTiger: engineConfig: cacheSizeGB: 1这个值给多少合适我的经验是虚拟机内存的 25% 到 40% 之间。4GB 的机器给 1GB8GB 的机器给 2 到 3GB16GB 的可以给 4 到 6GB。给太少会频繁读盘导致评测时卡顿给太多会挤占 Node 和评测沙箱的空间。安全方面再强调一次/etc/mongod.conf里的bindIp保持127.0.0.1不要改成0.0.0.0。数据库端口暴露出去等于把全部题目和用户数据摆在大街上。Hydro 的 Web 服务在同一台机器上走本地回环访问完全够用。3.2 Node.js 版本和依赖源的加速Hydro 的运行需要 Node.js版本要求跟着 Hydro 自身的版本走新版本一般要求 18 或 20 以上。我建议直接用 NodeSource 的源装别用系统自带的 apt 版本Ubuntu 仓库里的 Node 通常偏老curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs node -v npm -v国内网络环境下载 npm 包会比较慢改一下源能明显提速npm config set registry https://registry.npmmirror.com yarn config set registry https://registry.npmmirror.com这里有个容易踩的坑Hydro 用的是 Yarn 1.x 那套工作区机制如果你手贱装了 Yarn 3 或者 4也就是所谓的 Berry构建时会出现一堆 PnP 相关的报错。所以全局安装的时候一定要指定 Yarn 1 的最后一个版本装完用yarn -v确认输出是1.22.x这种格式。还有一个小细节yarn global add装的包默认在~/.yarn/bin目录下这个目录不一定在PATH里。如果是用 root 装的路径通常是/usr/local/bin反而没这个问题。所以我的习惯是全程用普通用户加sudo操作遇到命令找不到的时候先which hydrooj看一眼找不到就检查 PATH。3.3 评测沙箱最容易被忽略但决定成败的一环Hydro 本身不直接运行用户提交的代码真正干这件事的是一个独立的评测沙箱程序。如果没有它你点提交之后页面会一直显示等待评测然后就没有然后了。我见过不少人卡在这一步以为是自己代码有问题其实服务端压根没在跑评测。沙箱程序的部署方式有两种一键脚本会帮你自动下载对应架构的二进制文件并放到合适的目录手动部署的话需要自己去项目发布页下载注意选对架构绝大多数虚拟机是amd64树莓派或者某些 ARM 服务器是arm64下载之后给可执行权限放到PATH覆盖得到的目录里。沙箱对权限比较敏感。它需要限制用户进程能用的系统调用、能用的内存、能用的 CPU 时间这些能力在不同内核版本上实现方式不一样。如果在容器里跑宿主机的 seccomp 策略可能会拦住沙箱的部分操作表现为评测进程启动后立刻退出。这种情况我一般先在裸机上验证沙箱能跑通再考虑容器化。验证沙箱是否正常最直接的办法是在 Hydro 里给自己开一道 AB 的简单题用 C 或者 Python 提交一次看能不能拿到结果。能拿到Accepted说明整条链路从 Web 到数据库到沙箱全部通畅。4. 两条部署路径一键脚本和手动安装4.1 一键脚本替你做了哪些事Hydro 官方提供了一键安装脚本在 Debian 系系统上执行一条命令就能把整套环境拉起来包括装 MongoDB、装 Node、装 Yarn、全局安装 Hydro、安装默认 UI 插件、生成 systemd 服务单元、最后启动服务。对于只是想快速跑通的人来说这是最省事的路径。需要提醒的是脚本的地址会随版本更新别抄博客里三五年前的那条 curl 命令去官方文档页面上复制当前的那条。另外一键脚本对系统版本有假设跑在非 Debian 系系统上可能中途失败。执行之前我一般会做两件事一是确保curl和git已经装上二是先给虚拟机打个快照。因为脚本一旦跑到一半失败了环境会处于半残状态回滚比重来快得多。脚本执行完之后用这几条命令确认状态systemctl status mongod systemctl status hydro ss -lntp | grep 8888三条都正常就可以在宿主机浏览器里打开http://虚拟机IP:8888了。4.2 手动部署的完整过程想搞清楚每一步在干什么或者脚本在你机器上失败了就走手动这条路。我在下面把关键环节列出来具体的包版本按当前官方文档来。第一步准备基础工具和用户sudo apt update sudo apt install -y curl gnupg git nginx sudo useradd -r -m -d /data/hydro -s /bin/bash hydro第二步装 MongoDB 并确认能连上这一步前面 3.1 讲过了。第三步装 Node.js 和 Yarn 1前面 3.2 讲过了。第四步全局安装 Hydro 和默认界面插件sudo yarn global add hydrooj sudo hydrooj addon add hydrooj/ui-defaultaddon add这条命令的作用是把界面插件注册到 Hydro 的插件列表里不加的话能打开接口但看不到正常的页面。这也是新手最容易漏掉的一步。第五步先手动跑一次确认没问题再交给 systemdsudo -u hydro hydrooj --port8888 --host 0.0.0.0用一个普通用户跑是为了避免整站以 root 身份运行——评测沙箱要以低权限身份执行陌生代码这一点特别重要。看到控制台打出监听日志之后宿主机浏览器打开页面能显示说明配置正确按 CtrlC 停掉进入下一步。4.3 用 systemd 托管让它开机自启、挂了自动拉起Hydro 支持被 systemd 托管也能被 PM2 之类的进程管理器托管。我倾向 systemd因为它是系统自带的少装一个组件而且日志直接进 journald查起来方便。下面是服务单元的样子[Unit] DescriptionHydro Online Judge Afternetwork.target mongod.service Wantsmongod.service [Service] Typesimple Userhydro Grouphydro WorkingDirectory/data/hydro ExecStart/usr/local/bin/hydrooj --port8888 --host 0.0.0.0 Restartalways RestartSec5 EnvironmentNODE_ENVproduction StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target几个关键点单独说一下。ExecStart里必须写hydrooj的绝对路径因为 systemd 的PATH环境比你在终端里窄得多写相对命令名会报找不到命令。Userhydro保证进程以普通用户身份运行。Restartalways配合RestartSec5让它在异常退出后自动拉起来评测系统半夜崩了没人管这个配置能救你一命。保存到/etc/systemd/system/hydro.service然后sudo systemctl daemon-reload sudo systemctl enable --now hydro sudo systemctl status hydro sudo journalctl -u hydro -f最后那条journalctl -f是盯日志用的出问题的时候第一时间看这里比翻各种日志文件快得多。5. 用 Nginx 做入口转发顺便解决 WebSocket 和大文件上传5.1 为什么要在 Hydro 前面再放一层 NginxHydro 自己监听的 8888 端口对外直接暴露当然也能用但有两个明显短板。一是端口号难看每次访问都要记住:8888二是 HTTPS、大文件上传、超时时间这些都在这一层更好控制。所以正式一点的做法是在前面放一层 Nginx把 80 端口的请求转给本机的 8888。配置大概长这样server { listen 80; server_name oj.example.com; client_max_body_size 512m; location / { proxy_pass http://127.0.0.1:8888; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 300s; proxy_send_timeout 300s; } }5.2 逐行解释那几个容易被抄漏的参数proxy_http_version 1.1加Upgrade和Connection两个头是为了让 WebSocket 能穿透这一层。Hydro 的比赛页面排行榜、评测状态推送都走 WebSocket这三个少了任何一个页面能打开但实时数据永远不刷新。client_max_body_size 512m是允许上传的最大请求体积。你导入一套带完整测试数据的题目压缩包几百 MB 很正常用默认的 1MB 限制会直接返回 413 错误。这个值我一般给到 512MB够用了别开到几个 G容易被人拿来做别的事。X-Real-IP和X-Forwarded-For这两行是为了让 Hydro 能拿到访问者的真实 IP。不加的话所有记录里的 IP 都是127.0.0.1做比赛防作弊或者排查异常提交时会很难受。proxy_read_timeout 300s是为长时间请求留余量。比如导出大量提交记录、生成比赛成绩单这种操作几秒钟可能跑不完默认 60 秒会断开。配置改完执行sudo nginx -t检查语法再sudo systemctl reload nginx生效。这里我踩过一次坑配置文件里server_name写了个域名但测试的时候用的是 IP 访问结果 Nginx 把请求路由到了默认站点返回一个欢迎页。要么把server_name改成_要么把域名解析配上别让请求落到默认站点上。5.3 HTTPS 要不要上如果只是内网环境自己用HTTP 就够了别折腾证书。如果要把系统放到公网、让外校同学参加比赛那 HTTPS 基本是必须的——现代浏览器对 HTTP 页面会显示不安全警告而且某些功能比如剪贴板接口只在安全上下文里可用。申请证书这块现在流程已经很成熟了用通用工具自动申请加自动续期几分钟的事。唯一需要注意的一点是启用 HTTPS 之后Hydro 里配置的站点地址也要同步改成https://开头否则系统生成的一些回调链接和邮件链接仍然是 http 的会出现混合内容被浏览器拦截的情况。6. 上线之后的运维备份、升级和评测扩容6.1 数据备份出事之前做不是出事之后想MongoDB 自带mongodump和mongorestore两个工具这是最基本的备份手段mongodump --db hydro --out /data/backup/$(date %F)这条命令把hydro数据库完整导出成 BSON 文件恢复的时候用mongorestore指回去就行。注意导出期间对数据库有读压力比赛高峰别执行我一般放在凌晨的低谷时段。除了数据库还有两样东西要一起备份一是 Hydro 的工作目录里面存着上传的题目附件、用户头像这类文件二是你的配置文件包括/etc/mongod.conf、/etc/systemd/system/hydro.service、Nginx 的站点配置。这三样凑齐换台机器十分钟就能恢复出一套一模一样的系统。用 crontab 做定时任务注意加日志重定向不然出错的时候你完全不知道0 3 * * * /usr/bin/mongodump --db hydro --out /data/backup/$(date \%F) /var/log/hydro-backup.log 21保留策略上我一般保留最近 14 天的完整备份每周再额外保留一份到独立磁盘上。虚拟机磁盘一旦损坏跟它放在同一块盘上的备份也一起没了这一点很多人想不到。6.2 升级 Hydro 的正确姿势Hydro 迭代速度不慢新版本会修 bug 也会带来新功能。升级流程我固化成了四步一步都不能省先备份。升级失败要回滚没备份就只能重装。打快照。虚拟机的优势就在这里升级前打一个出问题直接回滚到升级前状态比任何回滚脚本都快。更新包。执行全局安装命令把 Hydro 更新到最新版然后重新执行一次hydrooj addon add更新插件。看日志确认。journalctl -u hydro -f盯一到两分钟确认没有数据库迁移报错。注意Hydro 的某些版本升级会涉及数据库结构变更第一次启动时自动执行迁移。迁移过程中不要中途重启服务否则数据库可能处于中间状态。我一般的做法是升级前把数据库也完整 dump 一份迁移出问题时可以恢复到升级前的结构。6.3 评测能力的扩展思路单机跑到几十人的规模还没什么问题上百人同时提交评测队列就会开始堆积页面上的状态会长时间停在等待评测。这时候有几个方向可以走。一是给虚拟机加核加内存。评测沙箱是并发跑的CPU 核数直接决定能同时判多少份代码。从 4 核加到 8 核吞吐量大概能翻一倍。二是把评测进程拆出来单独跑。较新版本的 Hydro 支持把 Web 服务和评测角色分开启动具体的启动参数写法和配置项建议直接看hydrooj --help的输出版本之间变化比较大硬抄老教程很容易起不来。拆开之后Web 机器专注处理页面和接口评测机器专注判题两边互不干扰。三是限制单个评测的资源上限。在后台设置里可以给每道题指定时间限制和内存限制这个值别设得太宽松。我见过有人把所有题目统一设成 5 秒 512MB结果一个死循环提交就能吃掉一个核心好几分钟队列直接堵死。合理的做法是按题目类型区分简单题 1 秒 256MB复杂算法题 2 到 3 秒 512MB别给到几十秒。7. 踩坑记录那几次让我熬到凌晨的报错7.1 mongod 启动就退出日志里只有一行 Illegal instruction这个坑我在一台 2012 年的老笔记本上遇到过当时第一反应是磁盘满了或者权限不对查了半天磁盘、查了文件属主全部正常最后才在/var/log/mongodb/mongod.log里看到那行Illegal instruction。原因就是这台机器的 CPU 不支持 AVX装的是 MongoDB 6.0。解决办法有两条要么降级到 MongoDB 4.4要么在虚拟机设置里把 AVX 指令透传给客户机。降级更省事但要注意 4.4 版本对 Ubuntu 22.04 的支持情况可能得手动加源。这条经验告诉我装数据库之前先跑一遍grep -o avx /proc/cpuinfo一秒钟的事能省两小时。7.2 页面能打开提交之后一直显示等待评测这个现象我第一次遇到的时候查错了方向以为是前端的问题把界面插件卸了重装没用。真正的原因在沙箱那一层。排查链路是这样的先在虚拟机里看 Hydro 的日志没有明显报错然后手动在命令行里跑一次沙箱程序发现它启动后立刻退出退出码不是 0继续查发现是沙箱文件没有可执行权限之前用普通用户下载的权限被设成了 644。加个chmod x之后正常了。后来我又遇到过几次类似现象原因各不相同有的是沙箱路径没写进 systemd 的PATH有的是虚拟机的内核版本太老不支持某些系统调用还有一次是内存不够沙箱 fork 子进程的时候被 OOM Killer 杀了。所以遇到一直等待评测第一件事就是去看服务日志别在页面上瞎点。7.3 虚拟机装系统蓝屏或者提示需要管理员权限热搜里虚拟机安装linux蓝屏和vm虚拟机修复时显示需要管理员权限这两个词我很有共鸣。前者刚才说过了八成是 BIOS 虚拟化没开或者虚拟化软件跟系统自带的 Hyper-V 冲突。Windows 上的 Hyper-V 会独占虚拟化能力导致 VMware 只能以兼容模式运行性能差还会出各种奇怪问题。解决办法是在启用或关闭 Windows 功能里把 Hyper-V 相关项取消勾选重启再试一次。后者通常是虚拟机软件本身的安装或修复需要管理员权限右键用管理员身份运行安装程序就行。还有一种情况是你把虚拟机文件放在了需要权限的目录里比如C:\Program Files下面换到用户目录下重新创建就能解决。我现在的习惯是统一放在D:\VMs\这种没什么权限限制的路径下。7.4 上传的测试数据包解压出来全是乱码从别人那里拿到题目数据压缩包传到 Linux 里解压中文文件名变成一堆问号或者奇怪的方块这是编码问题。Windows 下用压缩软件打出来的 zip文件名通常按 GBK 编码存而 Linux 默认按 UTF-8 解析两边对不上就乱码了。处理办法如果系统装了 unzip可以用unzip -O GBK data.zip指定编码更好的做法是用7z或者unar它们对编码的自动探测更聪明一些sudo apt install p7zip-full 7z x data.zip -o./data如果只是内容乱码而不是文件名乱码那多半是文件本身就是 GBK 编码的文本用iconv -f GBK -t UTF-8 input.txt -o output.txt转一下就行。为了避免这类反复出现的问题我现在拿到压缩包第一件事是file -i data.zip看一眼编码信息。最后分享两个我用了很久、确实省事的小习惯。第一个是每次部署完拍完快照之后把这次用到的所有命令按顺序记在一个文本文件里放在虚拟机桌面上或者/root/deploy-notes.md。别觉得麻烦几个月后你要么是给第二台机器部署要么是把整套东西搬到服务器上有这个文件在十分钟就能复现比到处翻历史记录强太多。第二个是给虚拟机的磁盘单独挂一块虚拟硬盘专门放 MongoDB 数据和题目附件系统盘只放系统。这样一来备份只需要对着数据盘操作扩容的时候也能单独扩数据盘不用动系统。我吃过一次系统盘被日志撑满、连 SSH 都连不进去的亏之后就一直这么干了。