web-dev-qa-db-fra.com

Délai d'attente de Docker pour le conteneur?

Pour ma thèse à l'université, je travaille sur un système de classement par codes dans lequel les utilisateurs peuvent compiler/exécuter du code non fiable via des conteneurs temporaires. Le système semble bien fonctionner jusqu'à présent, mais l'un des problèmes auquel je suis confronté est que, lorsque le code d'une boucle infinie est soumis, E.g:

while True:
   print "infinite loop"

le système tourne en rond. Le problème est que lorsque je crée un nouveau conteneur Docker, l'interpréteur Python empêche le menu fixe de tuer le conteneur enfant car les données sont toujours en cours d'impression sur STDOUT (pour toujours). Cela conduit à l'énorme vulnérabilité de docker consommant toutes les ressources système disponibles jusqu'à ce que la machine utilisant le système se bloque complètement (voir ci-dessous):

enter image description here

Ma question est donc la suivante: existe-t-il un meilleur moyen de définir un délai d’expiration sur un conteneur Docker que ma méthode actuelle qui va réellement tuer le conteneur Docker et sécuriser mon système (code originellement extrait de ici )?

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

Edition: le délai d’expiration par défaut dans mon application (transmis à la variable $to) est "10s"/10 secondes.


J'ai déjà essayé d'ajouter directement une minuterie et sys.exit() à la source python, mais ce n'est pas vraiment une option viable, car elle semble plutôt peu sûre, car l'utilisateur pourrait soumettre du code pour l'empêcher de s'exécuter, ce qui signifierait que le problème persisterait. Oh les joies d'être coincé sur une dissertation ... :(

24
Joel Murphy

Vous pouvez configurer votre conteneur avec une ulimit sur le temps processeur maximal, ce qui supprimera le processus de mise en boucle. Un utilisateur malveillant peut contourner ce problème, s’il est root dans le conteneur.

Il y a un autre S.O. question, " Définition de limites absolues sur le processeur pour les conteneurs Docker " décrivant comment limiter la consommation de processeur des conteneurs. Cela vous permettrait de réduire l’effet des utilisateurs malveillants.

Je suis cependant d’accord avec Abdullah pour dire que vous devriez pouvoir docker kill le fugitif de votre superviseur.

3
Nathaniel Waisbrot

J'ai trouvé une solution à ce problème.

Tout d’abord, vous devez tuer le conteneur Docker lorsque le délai est atteint:

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

Le conteneur s'exécute en mode détaché (option -d), de sorte qu'il s'exécute en arrière-plan. Vous exécutez également sleep en arrière-plan. Attendez ensuite que le conteneur s'arrête. S'il ne s'arrête pas dans 10 secondes (veille programmée), le conteneur sera tué.

Comme vous pouvez le constater, le processus d'exécution du menu fixe appelle un script nommé 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

Il commence par compiler et exécuter un programme C (c'est mon cas d'utilisation, je suis sûr que la même chose peut être faite pour Python Compiller).

Cette partie:

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

Est responsable de la taille de sortie maximale. Il permet une sortie maximale de 1 Mo.

Après cela, je vérifie juste si le fichier est 1MB. Si la valeur est true, écrivez un message à l'intérieur (au début) du fichier de sortie.

1
Pablo Werlang

Si vous souhaitez exécuter les conteneurs sans fournir de protection à l'intérieur de ceux-ci, vous pouvez utiliser les contraintes d'exécution sur les ressources .

Dans votre cas, -m 100M --cpu-quota 50000 pourrait être raisonnable.

De cette façon, les ressources système des parents ne seront pas consommées tant que vous ne pourrez pas les tuer.

0
ctolsen

Je suppose que vous pouvez utiliser des signaux en python comme unix pour définir le délai d’expiration. vous pouvez utiliser une alarme d'une heure précise, par exemple 50 secondes, et l'attraper. Le lien suivant peut vous aider. signaux en python

0
Nitin Tripathi