Running Judge0 in cgroup v1

Ayush KumarAyush Kumar
3 min read

Judge0 has a modular microservices-based architecture that looks something like this:

  1. API Server (REST API)

  2. Worker(s) (Isolated sandboxes that run user code)

  3. Database (PostgreSQL, for metadata about submissions)

  4. Message Queue (Redis Pub/Sub or optionally RabbitMQ)

[User submits code via frontend] → [Judge0 REST API] → [PostgreSQL]
                                                     ↓
                                          [Redis PubSub queue]
                                                     ↓
                                         [Judge0 Worker picks job]
                                                     ↓
                                       [Runs in isolated container]
                                                     ↓
                              [Collect output/errors/time/memory usage]
                                                     ↓
                                        [Store results in PostgreSQL]
                                                     ↓
                                 [User polls or gets notified of result]
  • Judge0 uses isolate sandbox that creates a temporary directory like /box, runs the code inside it, and deletes after execution.

  • Isolate Uses cgroups v1 to enforce memory limits (which is why your error occurs when it can’t write to /sys/fs/cgroup/memory/box-*).

    • Control Groups (cgroups):

      Cgroups are a Linux kernel feature that lets you limit, monitor, and isolate the resource usage (CPU, memory, disk I/O, etc.) of a process or a group of processes.

    • which is why systemd.unified_cgroup_hierarchy=0 is recommended to disable cgroup v2 (which uses a unified hierarchy and doesn’t have the same memory interface layout).

Judge0 worker requires cgroup v1, and strict memory sandboxing needs:

  • Host with cgroupv1

  • /sys/fs/cgroup to be writable (bind-mounted)

  • privileged mode in Docker

  • SYS_ADMIN, SYS_RESOURCE capabilities

Otherwise: You’ll hit the Cannot write /sys/fs/cgroup/memory/box-N/memory.limit_in_bytes error.

Newer versions of linux ( eg. ubuntu ) come with cgoup v2 , which offical doc. of judge0 try to buypass by updating /etc/default/grub . But newer versions makes it hard to fully use cgroup v1 with memory control, due to which Judge0 won’t work reliably using default Isolate configuration.

Hence, local development is DOOMED !!

Solution

  • Creating a LOCAL VM ( like t2.micro on AWS ) with ubuntu 20.04 as it gives full cgroup v1 write access.

  • Steps:

  • Create and ssh into VM like :

      multipass launch 20.04 --name judge0-vm --memory 2G --disk 30G --cpus 3
      multipass shell judge0-vm
    
  • Run in vm :

    
      # Install dependencies
      sudo apt update && sudo apt upgrade -y
      sudo apt install ca-certificates curl gnupg lsb-release -y
    
      # Add Docker GPG key
      sudo install -m 0755 -d /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
          sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
      sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
      # Set up repository
      echo \
        "deb [arch=$(dpkg --print-architecture) \
        signed-by=/etc/apt/keyrings/docker.gpg] \
        https://download.docker.com/linux/ubuntu \
        $(lsb_release -cs) stable" | \
        sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
      # Install Docker Engine and Docker Compose Plugin
      sudo apt update
      sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
    
      # Optional: run without sudo
      sudo usermod -aG docker $USER
      newgrp docker
    
  • Install judge0

      wget https://github.com/judge0/judge0/releases/download/v1.13.1/judge0-v1.13.1.zip
      unzip judge0-v1.13.1.zip
    
  • update REDIS & PG PASSWORD in judge0.conf .

  • run the judge0 stack →

docker compose up

  • Get vm ip

      ubuntu@judge0-vm:~/judge0-v1.13.1$ ip a | grep inet
          inet 127.0.0.1/8 scope host lo
          inet6 ::1/128 scope host 
          inet 10.130.253.46/24 metric 100 brd 10.130.253.255 scope global ens3
          inet6 fe80::5054:ff:fe8f:bc45/64 scope link 
          inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
          inet 172.18.0.1/16 brd 172.18.255.255 scope global br-93b092c155bf
          inet6 fe80::8450:dbff:fe0b:96a0/64 scope link
    
    • Use vm’s ip to communicate eg: 10.130.253.46
  • Submit and GetResult

Thankyou ……………

0
Subscribe to my newsletter

Read articles from Ayush Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayush Kumar
Ayush Kumar