web-dev-qa-db-ja.com

コンテナーのDockerタイムアウト?

大学の論文では、ユーザーが一時的なDockerコンテナーを介して信頼できないコードをコンパイル/実行できるコーディングリーダーボードシステムに取り組んでいます。これまでのところシステムはうまく機能しているようですが、私が直面している問題の1つは、無限ループのコードが送信されると、

_while True:
   print "infinite loop"
_

システムが問題を起こす。問題は、新しいdockerコンテナーを作成しているときに、PythonインタープリターがデータがSTDOUTに(永久に)印刷されているため、Dockerが子コンテナーを強制終了できないようにすることです。これにより、巨大なシステムを使用しているマシンが完全にフリーズするまで、利用可能なすべてのシステムリソースを食い尽くすドッカーの脆弱性(以下を参照):

enter image description here

だから私の質問は、現在の方法よりもDockerコンテナにタイムアウトを設定するより良い方法がありますか?実際にDockerコンテナを殺してシステムを安全にします(元々 here から取得したコード)?

_#!/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_変数に渡される)は「10秒」/ 10秒です。


タイマーとsys.exit()をpythonソースに直接追加することを検討しましたが、これは実際に実行可能なオプションではありません。ユーザーが実行しないようにコードを送信してください。つまり、問題が引き続き発生します。ああ、論文にこだわる喜び... :(

26
Joel Murphy

ループプロセスを強制終了する最大CPU時間でulimitを使用してコンテナーを設定できます。ただし、悪意のあるユーザーがコンテナー内のrootであれば、これを回避できます。

別のS.O.があります。質問、「 DockerコンテナーのCPUの絶対制限の設定 」は、コンテナーのCPU消費を制限する方法を説明しています。これにより、悪意のあるユーザーの影響を減らすことができます。

ただし、監督者からの暴走をdocker killできるようにすべきであることにアブドラは同意します。

3

私はこの問題の解決策を達成しました。

最初に、時間制限に達したときに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オプション)で実行されるため、バックグラウンドで実行されます。次に、バックグラウンドでもスリープを実行します。次に、コンテナが停止するのを待ちます。 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 compiller)でも同じことができると確信しています)。

この部分:

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

最大出力サイズのものに責任があります。出力を最大1MBにすることができます。

その後、ファイルが1MBかどうかを確認します。 trueの場合、出力ファイルの内部(先頭)にメッセージを書き込みます。

1
Pablo Werlang

コンテナーを保護せずにコンテナーを実行する場合は、 リソースのランタイム制約 を使用できます。

あなたの場合、-m 100M --cpu-quota 50000は妥当かもしれません。

そうすれば、あなたがそれを殺すことに取り掛かるまで、それは親のシステムリソースを使い果たしません。

0
ctolsen

おそらく、python unixのようにタイムアウトを設定するために信号を使用できます。50秒などの特定の時間のアラームを使用して、それをキャッチできます。次のリンクが役立つ場合があります。 signals in python

0
Nitin Tripathi