Docker容器超时问题?

30

我正在撰写大学的论文,涉及编程排行榜系统,用户可以通过临时的docker容器编译/运行不受信任的代码。目前看来系统运行良好,但我面临的一个问题是,当提交无限循环的代码时,例如:

while True:
   print "infinite loop"

系统失控了。问题在于,当我创建一个新的docker容器时,Python解释器会阻止docker杀死子容器,因为数据仍然被打印到STDOUT(永远)。这导致docker吃掉所有可用的系统资源,直到使用该系统的机器完全冻结(如下所示):

enter image description here

所以我的问题是,有没有比我目前的方法更好的设置docker容器超时的方法,这将实际上“终止”docker容器并使我的系统更安全(代码最初来自此处)?
#!/bin/bash
set -e

to=$1
shift

cont=$(docker run --rm "$@")
code=$(timeout "$to" docker wait "$cont" || true)
docker kill $cont &> /dev/null
echo -n 'status: '
if [ -z "$code" ]; then
    echo timeout
else
    echo exited: $code
fi

echo output:
# pipe to sed simply for pretty nice indentation
docker logs $cont | sed 's/^/\t/'

docker rm $cont &> /dev/null

编辑:我的应用程序中默认的超时时间(传递给$to变量)为“10s” / 10秒。


我尝试过直接在Python源代码中添加计时器和sys.exit(),但这并不是一个可行的选择,因为它似乎相当不安全,因为用户可以提交代码以防止其执行,这意味着问题仍然存在。哦,被卡在论文上的快乐... :(

2
我可能漏掉了什么,但为什么你不能像这样做:ID=$(docker run -d unsecure) && docker run --rm cleanup $ID,其中cleanup是一个容器,在X秒后杀死另一个容器? - Abdullah Jibaly
"永远" - 让我们尝试减小stdout缓冲区的大小。发送信号后,您的容器化Python进程处于什么状态? - Brian Cain
你可以使用Python的资源库设置CPU时间限制。使用ast,Python脚本可以在运行时进行检查和更改。 - Padraic Cunningham
你能提供一些命令的例子吗:docker run --rm=true -ti -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:2 python your-daemon-or-script.py . 我不明白你何时决定杀死它? - Valeriy Solovyov
6个回答

3
您可以在容器中设置ulimit来限制最大CPU时间,以杀死循环进程。不过,如果恶意用户在容器内部具有root权限,则可以绕过此限制。
还有一个S.O.问题,"Setting absolute limits on CPU for Docker containers",描述了如何限制容器的CPU消耗。这将使您能够减少恶意用户的影响。
不过,我同意Abdullah的看法,您应该能够通过监管程序docker kill运行失控的进程。

2
如果您想在容器内部不提供任何保护的情况下运行容器,您可以使用资源的运行时限制
在您的情况下,-m 100M --cpu-quota 50000 可能是合理的选择。
这样它就不会占用父进程的系统资源,直到您终止它。

1
我已经找到了这个问题的解决方案。
首先,当时间限制达到时,您必须杀死Docker容器:
#!/bin/bash
set -e
did=$(docker run -it -d -v "/my_real_path/$1":/usercode virtual_machine ./usercode/compilerun.sh 2>> $1/error.txt)
sleep 10 && docker kill $did &> /dev/null && echo -n "timeout" >> $1/error.txt &
docker wait "$did" &> /dev/null
docker rm -f $ &> /dev/null

容器以分离模式(-d选项)运行,因此在后台运行。 然后您还可以将sleep放在后台运行。 然后等待容器停止。如果它在10秒内没有停止(睡眠计时器),则容器将被终止。
正如您所看到的,docker run进程调用名为compilerun.sh的脚本:
#!/bin/bash
gcc -o /usercode/file /usercode/file.c 2> /usercode/error.txt && ./usercode/file < /usercode/input.txt | head -c 1M > /usercode/output.txt
maxsize=1048576
actualsize=$(wc -c <"/usercode/output.txt")
if [ $actualsize -ge $maxsize ]; then
    echo -e "1MB file size limit exceeded\n\n$(cat /usercode/output.txt)" > /usercode/output.txt
fi

它始于编译和运行一个C程序(这是我的用例,我相信同样的方法也适用于Python编译器)。
这部分内容:
command | head -c 1M > /usercode/output.txt

负责最大输出大小的事情。它允许最大输出为1MB。

之后,我只需检查文件是否为1MB。如果是,就在输出文件中(开头处)写入一条消息。


1

--stop-timeout选项在超时后无法终止容器。

相反,使用--ulimit --cpu=timeout选项来在超时时终止容器。 这基于容器内进程的CPU时间。


0

我猜,你可以在Python中像Unix一样使用信号来设置超时。你可以使用特定时间的闹钟,比如50秒,并捕获它。以下链接可能会对你有所帮助。 Python中的信号


-1
在运行Docker容器时,请使用--stop-timeout选项。一旦超时发生,它将执行SIGKILL。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接