大学の論文では、ユーザーが一時的なDockerコンテナーを介して信頼できないコードをコンパイル/実行できるコーディングリーダーボードシステムに取り組んでいます。これまでのところシステムはうまく機能しているようですが、私が直面している問題の1つは、無限ループのコードが送信されると、
_while True:
print "infinite loop"
_
システムが問題を起こす。問題は、新しいdockerコンテナーを作成しているときに、PythonインタープリターがデータがSTDOUTに(永久に)印刷されているため、Dockerが子コンテナーを強制終了できないようにすることです。これにより、巨大なシステムを使用しているマシンが完全にフリーズするまで、利用可能なすべてのシステムリソースを食い尽くすドッカーの脆弱性(以下を参照):
だから私の質問は、現在の方法よりも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ソースに直接追加することを検討しましたが、これは実際に実行可能なオプションではありません。ユーザーが実行しないようにコードを送信してください。つまり、問題が引き続き発生します。ああ、論文にこだわる喜び... :(
ループプロセスを強制終了する最大CPU時間でulimit
を使用してコンテナーを設定できます。ただし、悪意のあるユーザーがコンテナー内のrootであれば、これを回避できます。
別のS.O.があります。質問、「 DockerコンテナーのCPUの絶対制限の設定 」は、コンテナーのCPU消費を制限する方法を説明しています。これにより、悪意のあるユーザーの影響を減らすことができます。
ただし、監督者からの暴走をdocker kill
できるようにすべきであることにアブドラは同意します。
私はこの問題の解決策を達成しました。
最初に、時間制限に達したときに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の場合、出力ファイルの内部(先頭)にメッセージを書き込みます。
コンテナーを保護せずにコンテナーを実行する場合は、 リソースのランタイム制約 を使用できます。
あなたの場合、-m 100M --cpu-quota 50000
は妥当かもしれません。
そうすれば、あなたがそれを殺すことに取り掛かるまで、それは親のシステムリソースを使い果たしません。
おそらく、python unixのようにタイムアウトを設定するために信号を使用できます。50秒などの特定の時間のアラームを使用して、それをキャッチできます。次のリンクが役立つ場合があります。 signals in python