使用 docker 作为 online judge(OJ) 的 sandbox (1)

This article is deprecated, please see here for more details.

最近业务要实现在线代码判定(OJ)的功能,简单调研了一下,准备使用docker实现。业务流程大概如下:

大概的思路是:

  1. nginx 判定请求是否应该转发给 OJ 集群,比如:只要请求匹配 ^~ /oj 都转发给 docker 集群处理;
  2. docker 集群接收到请求后,先将代码保存在 web server 本地;
  3. 如果待判定的语言不需要编译即可执行 (比如PHP、Python),则直接保存在 web server 的某个目录下(例如 /tmp/oj);如果需要编译(比如 c、java),则先编译,将编译后的可执行文件保存在同一个目录下;
  4. 将 web server 上保存代码的目录(上文中的 /tmp/oj)挂载到 docker 镜像的某个目录下(例如 /mnt)
  5. 调用 docker 知行代码,并返回结果。

下面是相对详细的一些步骤:

安装 docker

# 参考官网
curl -sSL https://get.docker.com/ubuntu/ | sh
# 使用 ubuntu 作为镜像
docker pull ubuntu

升级 docker 镜像中的 OS

# 跑起来
docker run -it centos:6.6 /bin/sh
# 升级
apt-get update && apt-get upgrade -y
# 必要的安装包(Python 2.7.6 / PHP 5.5.9 / Perl 5.18.2 / gcc 4.8.4)
apt-get install perl python php5 php5-cli gcc g++

将镜像提交到 docker hub

# 使用 hub.docker.com 上的账户登录
docker login
# 将我们自己的镜像提交上去,其中 4a052bcdb3a8 是 docker ps -a 显示的容器id
docker commit -m "init from ubuntu" -a "<your_name>" 4a052bcdb3a8 <your_name>/<image_name>
docker push <your_name>/<image_name>

业务上处理提交过来的代码

# 如果需要编译,则在 web server 上先编译
source /etc/profile && /usr/bin/gcc <code_file> -o <target_file> 2>&1
# 使用 docker run 初始化环境,其中的参数 --memory/--memory-swap/--cpu-quota 限制 docker 使用的资源
/usr/bin/docker run -it -d --memory="32M" --memory-swap="32M" --cpu-quota=75000 -v /tmp/oj/:/mnt/ --name <uniq_container_name> <your_name>/<image_name> /bin/sh
# 使用 docker exec 知行目标代码/可执行文件
/usr/bin/docker exec <container_id> <code_file> 2>&1

当然,上面的限制并不是特别完全。对于业务来讲,还有以下几个问题需要考虑:

  1. 前端超时的判定
  2. 执行代码的安全性
  3. docker container 的善后清理工作

Leave a Reply

Your email address will not be published. Required fields are marked *

*