Подтвердить что ты не робот

Время ожидания докера для контейнера?

Для моей диссертации в университете я работаю над системой кодирования лидеров, где пользователи могут компилировать/запускать ненадежный код через временные контейнеры докеров. Кажется, что система работает хорошо, но одна проблема, с которой я столкнулся, заключается в том, что, когда отправляется код для бесконечного цикла, например:

while True:
   print "infinite loop"

система переходит в сгусток. Проблема в том, что когда я создаю новый контейнер докеров, интерпретатор Python не позволяет докеру убивать дочерний контейнер, поскольку данные все еще печатаются в STDOUT (навсегда). Это приводит к огромной уязвимости докера, который съедает все доступные системные ресурсы до тех пор, пока машина, использующая систему, не замерзает (показано ниже):

enter image description here

Итак, мой вопрос: есть ли лучший способ установить тайм-аут в контейнере докера, чем мой текущий метод, который на самом деле будет убить контейнер докеров и сделать мою систему безопасной (код, первоначально взятый из здесь)?

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

Изменить: время ожидания по умолчанию в моем приложении (передано переменной $to) равно "10 с" /10 секунд.


Я попытался найти добавление таймера и sys.exit() к источнику python напрямую, но это не очень эффективный вариант, поскольку он кажется довольно небезопасным, потому что пользователь может отправить код, чтобы он не выполнялся, что означает проблема все равно сохранится. О, радости застряли на диссертации...: (

4b9b3361

Ответ 1

Вы можете настроить свой контейнер с ulimit на максимальное время процессора, что приведет к уловлению процесса цикла. Злоумышленник может обойти это, хотя, если они являются корнями внутри контейнера.

Там другой С.О. вопрос "Установка абсолютных пределов для ЦП для контейнеров Docker", который описывает, как ограничить потребление ЦП в контейнерах. Это позволит снизить влияние злонамеренных пользователей.

Я согласен с Абдуллой, однако, что вы должны иметь возможность docker kill убегать от своего руководителя.

Ответ 2

Я думаю, вы можете использовать сигналы в python как unix для установки таймаута. вы можете использовать будильник определенного времени, скажем, 50 секунд и поймать его. Следующая ссылка может вам помочь. сигналы в python

Ответ 3

Если вы хотите запускать контейнеры без обеспечения защиты внутри них, вы можете использовать ограничения времени выполнения ресурсов.

В вашем случае -m 100M --cpu-quota 50000 может быть разумным.

Таким образом, он не будет питаться материнскими системными ресурсами, пока вы не начнете его убивать.

Ответ 4

Я решил решение этой проблемы.

Сначала вы должны убить контейнер докера, когда достигнут предел времени:

#!/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 вызывает script с именем 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

Отвечает за максимальный размер. Он позволяет выводить максимум 1 МБ.

После этого я просто проверяю, является ли файл 1 МБ. Если true, напишите сообщение внутри (в начале) выходного файла.