Judge0 部署踩坑:/box/script.py 或者 /box/Main.java 不存在?其实是 cgroup 版本惹的祸

Judge0 1.13.1 依赖 cgroup v1,而 Ubuntu 22 默认使用 cgroup v2,导致沙箱无法创建 /box 目录,最终报错 No such file or directory @ rb_sysopen - /box/script.py

一、问题现象

在 Docker Compose 部署 Judge0 CE 1.13.1 后,无论提交 Java 还是 Python 代码,都返回 Internal Error,并提示找不到 /box 下的源文件。

示例请求(Python)

{
  "source_code": "print('hello')",
  "language_id": 71
}

错误响应

{
    "stdout": null,
    "stderr": null,
    "message": "No such file or directory @ rb_sysopen - /box/script.py",
    "status": {
        "id": 13,
        "description": "Internal Error"
    }
}

Java 提交同样失败

{
  "source_code": "public class Main { public static void main(String[] args){ System.out.println(\"hello\"); }}",
  "language_id": 62
}

返回:

{
    "message": "No such file or directory @ rb_sysopen - /box/Main.java"
}

Docker 容器日志中的关键报错

查看 judge0-workers 容器日志:

Failed to create control group /sys/fs/cgroup/memory/box-23/: No such file or directory
chown: cannot access '/box': No such file or directory

二、错误排查的弯路

最开始容易误判为:

  • source_code 参数格式错误
  • JSON 序列化问题
  • Judge0 API 调用方式不对
  • Docker volume 挂载失败
  • Main.java 文件名硬编码问题

但实际完全不是代码或请求格式的问题,根本原因在操作系统层面。

三、根本原因分析

1. Judge0 的沙箱机制

Judge0 使用 isolate 作为代码执行沙箱。执行流程如下:

isolate 创建 box
    ↓
创建 namespace
    ↓
创建 /box 沙箱目录
    ↓
将源代码写入 /box/script.py 或 /box/Main.java
    ↓
编译运行

2. 失败的根源:创建 box 失败

日志中明确提示:

Failed to create control group /sys/fs/cgroup/memory/box-23/

这意味着 isolate 在第一步就失败了,因此 /box 目录根本没被创建,后续写入文件自然报错“No such file or directory”。

3. cgroup v1 vs v2 不兼容

  • /sys/fs/cgroup/memorycgroup v1 的典型路径。
  • 而现代 Linux 发行版(Ubuntu 22+、Debian 12、WSL2、Docker Desktop 默认内核)已切换到 cgroup v2
  • cgroup v2 下,所有控制器统一在 /sys/fs/cgroup不存在 /sys/fs/cgroup/memory 这个子目录。
  • Judge0 1.13.1 内置的 isolate 仍按 cgroup v1 的路径工作,导致无法创建控制组,进而整个沙箱初始化失败。

4. 确认当前系统的 cgroup 版本

mount | grep cgroup

若输出包含 cgroup2 on /sys/fs/cgroup type cgroup2,说明是 v2。

再检查是否存在 v1 的 memory 目录:

ls /sys/fs/cgroup/memory

如果返回 No such file or directory,则确认为 cgroup v2 环境。

四、解决方案

核心思路:将系统切换回 cgroup v1

1. 修改 GRUB 启动参数

编辑 /etc/default/grub

sudo nano /etc/default/grub

找到 GRUB_CMDLINE_LINUX="" 这一行,添加参数禁用 cgroup v2:

GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=0"

如果已有其他参数,例如:

GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"

则追加:

GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 systemd.unified_cgroup_hierarchy=0"
2. 更新 GRUB 配置
sudo update-grub
3. 重启服务器
sudo reboot
4. 验证 cgroup v1 已生效

重启后执行:

ls /sys/fs/cgroup/memory

应该能看到类似 memory.limit_in_bytesmemory.stat 等文件。

额外:Docker Compose 配置调整(可选但建议)

确保 workers 服务拥有足够权限:

workers:
  image: judge0/judge0:1.13.1
  privileged: true          # 赋予容器特权模式
  cap_add:
    - SYS_ADMIN
  command: ["./scripts/workers"]
  volumes:
    - ./judge0.conf:/judge0.conf:ro
  restart: always

重新部署 Judge0

docker compose down -v
docker compose up -d

五、验证结果

重新提交测试代码:

{
  "source_code": "print('hello')",
  "language_id": 71
}

返回正常执行结果:

{
    "stdout": "hello\n",
    "time": "0.015",
    "memory": 3212,
    "stderr": null,
    "compile_output": null,
    "message": null,
    "status": {
        "id": 3,
        "description": "Accepted"
    }
}

Java 同样恢复正常。Judge0 + isolate 沙箱已完全工作。

六、总结

现象 直接原因 根本原因
/box/script.py 不存在 isolate 未能创建 /box 创建 cgroup 失败
Failed to create control group cgroup v2 路径与 isolate 不兼容 Judge0 1.13.1 依赖 cgroup v1

关键经验

  • 当你遇到 Judge0 返回 Internal Error 且消息为 No such file or directory @ rb_sysopen - /box/xxx 时,首先检查 cgroup 版本,而不是怀疑代码或 API 调用。
  • 现代 Linux 发行版默认 cgroup v2,而很多仍依赖 cgroup v1 的沙箱工具(如旧版 isolate)会因此崩溃。
  • 通过内核引导参数 systemd.unified_cgroup_hierarchy=0 切回 v1 是最直接有效的解决方案。

希望这篇记录能帮你少走弯路,让 Judge0 顺利跑起来!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐