wake-up-neo.com

Docker-Timeout für Container?

Für meine Dissertation an der Universität arbeite ich an einem Coding-Leaderboard-System, mit dem Benutzer nicht vertrauenswürdigen Code über temporäre Docker-Container kompilieren und ausführen können. Das System scheint bisher gut zu funktionieren, aber ein Problem ist, dass, wenn Code für eine Endlosschleife gesendet wird, z.

while True:
   print "infinite loop"

das system geht drunter und drüber. Das Problem ist, dass der Python-Interpreter beim Erstellen eines neuen Docker-Containers verhindert, dass Docker den untergeordneten Container beendet, da die Daten immer noch in STDOUT (für immer) gedruckt werden. Dies führt dazu, dass der Docker die verfügbaren Systemressourcen so lange aufzehrt, bis der Computer, auf dem das System ausgeführt wird, vollständig einfriert (siehe unten):

enter image description here

Meine Frage ist also, gibt es eine bessere Möglichkeit, ein Timeout für einen Docker-Container festzulegen als meine derzeitige Methode, die tatsächlich den Docker-Container beendet und mein System sicher macht (Code stammt ursprünglich aus hier )?

#!/bin/bash
set -e

to=$1
shift

cont=$(docker run --rm "[email protected]")
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

Bearbeiten: Das Standardzeitlimit in meiner Anwendung (an die Variable $to übergeben) beträgt "10s"/10 Sekunden.


Ich habe versucht, einen Timer und sys.exit() direkt zur Python-Quelle hinzuzufügen, aber dies ist keine praktikable Option, da es ziemlich unsicher erscheint, da der Benutzer Code senden könnte, um die Ausführung zu verhindern, was bedeutet, dass das Problem weiterhin bestehen bleibt. Oh, die Freuden, an einer Dissertation festzuhalten ... :(

24
Joel Murphy

Sie könnten Ihren Container mit einer ulimit für die maximale CPU-Zeit einrichten, wodurch der Schleifenprozess abgebrochen wird. Ein böswilliger Benutzer kann dies jedoch umgehen, wenn er sich innerhalb des Containers befindet.

Es gibt noch einen S.O. Frage, " Absolute Grenzen der CPU für Docker-Container festlegen " beschreibt, wie der CPU-Verbrauch von Containern begrenzt wird. Auf diese Weise können Sie die Auswirkungen böswilliger Benutzer reduzieren.

Ich stimme jedoch mit Abdullah überein, dass Sie in der Lage sein sollten, die Flucht vor Ihrem Vorgesetzten zu docker kill zu machen.

3

Ich habe eine Lösung für dieses Problem gefunden.

Zuerst müssen Sie den Docker-Container töten, wenn das Zeitlimit erreicht ist:

#!/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

Der Container wird im getrennten Modus (Option -d) ausgeführt. Er läuft also im Hintergrund. Dann wird der Ruhezustand auch im Hintergrund ausgeführt. . Dann warten Sie, bis der Container angehalten wird. Wenn es nicht innerhalb von 10 Sekunden stoppt (Sleep-Timer), wird der Container abgebrochen.

Wie Sie sehen, ruft der Docker-Run-Prozess ein Skript mit dem Namen compilerun.sh auf:

#!/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

Es beginnt mit dem Kompilieren und Ausführen eines C-Programms (es ist mein Anwendungsfall, ich bin sicher, dass das auch für Python-Compiller möglich ist).

Dieser Teil:

command | head -c 1M > /usercode/output.txt

Ist für die maximale Ausgabegröße verantwortlich. Die Ausgabe darf maximal 1 MB betragen.

Danach prüfe ich nur, ob die Datei 1 MB groß ist. Wenn ja, schreiben Sie eine Nachricht in die Ausgabedatei (am Anfang).

1
Pablo Werlang

Wenn Sie die Container ohne Schutz ausführen möchten, können Sie Laufzeiteinschränkungen für resources verwenden.

In Ihrem Fall könnte -m 100M --cpu-quota 50000 sinnvoll sein.

Auf diese Weise werden die Systemressourcen der Eltern nicht aufgebraucht, bis Sie es schaffen, sie zu töten.

0
ctolsen

Ich denke, Sie können Signale in Python wie Unix verwenden, um das Timeout einzustellen. Sie können einen Alarm für eine bestimmte Zeit, z. B. 50 Sekunden, verwenden und ihn abfangen. Der folgende Link kann Ihnen helfen. Signale in Python

0
Nitin Tripathi