Docker timeout para contenedor?

Para mi disertación en la Universidad, estoy trabajando en un sistema de tabla de clasificación de códigos donde los usuarios pueden comstackr / ejecutar código no confiable a través de contenedores temporales acoplables. El sistema parece estar funcionando bien hasta ahora, pero un problema al que me enfrento es que cuando se envía el código para un bucle infinito, por ejemplo:

while True: print "infinite loop" 

el sistema se vuelve loco El problema es que cuando estoy creando un nuevo contenedor de docker, el intérprete de Python evita que el docker mate el contenedor secundario ya que los datos todavía se imprimen en STDOUT (para siempre). Esto lleva a la enorme vulnerabilidad de que la ventana acoplable se consum todos los recursos del sistema disponibles hasta que la máquina que utiliza el sistema se congele por completo (se muestra a continuación):

introduzca la descripción de la imagen aquí

Entonces, mi pregunta es, ¿hay una mejor manera de establecer un tiempo de espera en un contenedor de la ventana acoplable que mi método actual que realmente mate al contenedor de la ventana acoplable y haga que mi sistema sea seguro (código tomado originalmente de aquí )?

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

Editar: El tiempo de espera predeterminado en mi aplicación (pasado a la variable $to ) es “10s” / 10 segundos.


He intentado buscar agregar un temporizador y sys.exit() a la fuente de python directamente, pero esta no es realmente una opción viable, ya que parece bastante insegura porque el usuario podría enviar un código para evitar que se ejecute, lo que significa el problema Todavía persistiría. Oh, las alegrías de estar atrapado en una disertación … 🙁

Puede configurar su contenedor con un ulimit en el tiempo máximo de CPU, lo que eliminará el proceso de bucle. Sin embargo, un usuario malintencionado puede evitar esto, si son root dentro del contenedor.

Hay otra pregunta de SO, ” Establecimiento de límites absolutos en la CPU para contenedores Docker ” que describe cómo limitar el consumo de CPU de los contenedores. Esto le permitiría reducir el efecto de usuarios malintencionados.

Sin embargo, estoy de acuerdo con Abdullah en que deberías poder docker kill un fugitivo de tu supervisor.

He logrado una solución para este problema.

Primero debes matar el contenedor de la ventana acoplable cuando se alcanza el límite de tiempo:

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

El contenedor se ejecuta en modo separado (opción -d), por lo que se ejecuta en segundo plano. Entonces corres el sueño también en el fondo. Luego espera a que el contenedor se detenga. Si no se detiene en 10 segundos (temporizador de apagado), el contenedor se eliminará.

Como puede ver, el proceso de ejecución de la ventana acoplable llama a un script llamado 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 

Comienza comstackndo y ejecutando un progtwig en C (es mi caso de uso, estoy seguro de que se puede hacer lo mismo para Python Compiller).

Esta parte:

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

Es responsable del tamaño máximo de salida. Permite que la salida sea de 1MB máximo.

Después de eso, acabo de comprobar si el archivo es de 1 MB. Si es verdadero, escriba un mensaje dentro (al comienzo de) el archivo de salida.

Supongo que puedes usar señales en Python como Unix para establecer el tiempo de espera. Puedes usar la alarma de tiempo específico digamos 50 segundos y atraparla. El siguiente enlace te puede ayudar. señales en python

Si desea ejecutar los contenedores sin proporcionar ninguna protección dentro de ellos, puede utilizar restricciones de tiempo de ejecución en los recursos .

En su caso, -m 100M --cpu-quota 50000 puede ser razonable.

De esa manera, no consumirá los recursos del sistema de los padres hasta que no logres matarlo.