Время ожидания докера для контейнера?
Для моей диссертации в университете я работаю над системой кодирования лидеров, где пользователи могут компилировать/запускать ненадежный код через временные контейнеры докеров. Кажется, что система работает хорошо, но одна проблема, с которой я столкнулся, заключается в том, что, когда отправляется код для бесконечного цикла, например:
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 напрямую, но это не очень эффективный вариант, поскольку он кажется довольно небезопасным, потому что пользователь может отправить код, чтобы он не выполнялся, что означает проблема все равно сохранится. О, радости застряли на диссертации...: (
Ответы
Ответ 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, напишите сообщение внутри (в начале) выходного файла.