2015-03-09 44 views
21

Đối với luận án của tôi tại Đại học, tôi đang làm việc trên một hệ thống bảng dẫn mã hóa nơi người dùng có thể biên dịch/chạy mã không đáng tin cậy thông qua các vùng chứa tạm thời. Hệ thống dường như hoạt động tốt cho đến nay, nhưng một vấn đề tôi đang gặp phải là khi mã cho một vòng lặp vô hạn được gửi, Ví dụ:Thời gian chờ của đế chế cho vùng chứa?

while True: 
    print "infinite loop" 

hệ thống đi haywire. Vấn đề là khi tôi đang tạo một container docker mới, trình thông dịch Python ngăn cản docker giết chết container con khi dữ liệu vẫn đang được in tới STDOUT (mãi mãi). Điều này dẫn đến lỗ hổng khổng lồ của Docker ăn lên tất cả các tài nguyên hệ thống có sẵn cho đến khi máy sử dụng hệ thống hoàn toàn bị đóng băng (hình dưới đây):

enter image description here

Vì vậy, câu hỏi của tôi là, là có một cách tốt hơn để thiết lập một thời gian chờ trên một docker container hơn so với phương pháp hiện tại của tôi mà thực sự sẽ làm giết container docker và làm cho hệ thống của tôi an toàn (mã ban đầu được lấy từ 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 

Chỉnh sửa: Thời gian chờ mặc định trong đơn của tôi (được chuyển đến số $to biến) là "10s"/10 giây.


Tôi đã cố gắng tìm cách thêm một bộ đếm thời gian và sys.exit() đến nguồn python trực tiếp, nhưng điều này là không thực sự là một lựa chọn khả thi vì nó có vẻ khá an toàn vì người dùng có thể gửi mã để ngăn chặn nó từ thực hiện, có nghĩa là vấn đề vẫn tồn tại. Oh những niềm vui của bị mắc kẹt trên một luận án ... :(

+2

Tôi có thể thiếu một thứ gì đó, nhưng tại sao bạn không thể làm điều gì đó như: 'ID = $ (docker run -d unsecure) && docker run --rm cleanup $ ID', nơi dọn dẹp là một container chứa một container khác sau X giây? –

+0

"forever" - hãy thử giảm kích thước bộ đệm stdout. Trạng thái của quá trình container-'python' của bạn là gì sau khi bạn gửi tín hiệu? –

+0

Bạn có thể đặt giới hạn về thời gian cpu bằng cách sử dụng python với tài nguyên lib, một tập lệnh python có thể được kiểm tra và thay đổi khi chạy bằng cách sử dụng ast –

Trả lời

3

Bạn có thể thiết lập vùng chứa của mình với ulimit trên thời gian CPU tối đa, điều này sẽ giết chết quá trình lặp. nếu họ gốc bên trong container.

có một câu hỏi SO, "Setting absolute limits on CPU for Docker containers" mô tả làm thế nào để hạn chế tiêu thụ CPU của container. Điều này sẽ cho phép bạn để giảm tác động của người dùng nguy hiểm.

tôi đồng ý Tuy nhiên, với Abdullah, bạn nên có thể docker kill người chạy trốn khỏi người giám sát của bạn

0

Tôi đoán, bạn có thể sử dụng tín hiệu trong python như unix để đặt thời gian chờ. bạn có thể sử dụng báo thức của thời gian cụ thể nói 50 giây và bắt nó. Liên kết sau đây có thể giúp bạn. signals in python

0

Nếu bạn muốn chạy các vùng chứa mà không cung cấp bất kỳ sự bảo vệ nào bên trong chúng, bạn có thể sử dụng runtime constraints on resources.

Trong trường hợp của bạn, -m 100M --cpu-quota 50000 có thể hợp lý.

Bằng cách đó, nó sẽ không ăn hết tài nguyên hệ thống của cha mẹ cho đến khi bạn bắt đầu giết nó.

0

Tôi đã đạt được giải pháp cho vấn đề này.

Trước tiên, bạn phải giết chứa Docker khi thời hạn được thực hiện:

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

Các chạy chứa trong chế độ tách ra (tùy chọn -d), do đó nó chạy ở chế độ nền. Sau đó, bạn chạy chế độ ngủ cũng ở chế độ nền. Sau đó đợi hộp chứa dừng lại. Nếu nó không dừng lại trong 10 giây (giờ giấc ngủ), thùng chứa sẽ bị giết.

Như bạn thấy, quá trình Docker chạy gọi một kịch bản có tên 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 

Nó bắt đầu bằng cách biên dịch và chạy một chương trình C (trường hợp sử dụng của tôi của nó, tôi chắc chắn như vậy có thể được thực hiện cho trình biên dịch python).

phần này:

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

Chịu trách nhiệm điều kích thước đầu ra tối đa. Nó cho phép đầu ra tối đa 1MB.

Sau đó, tôi chỉ kiểm tra xem tệp có là 1MB không. Nếu đúng, hãy viết một thông báo bên trong (ở đầu) tập tin đầu ra.

Các vấn đề liên quan