#python #c #docker #subprocess #resources
Вопрос:
Я изучал, как предоставить собственный Python subprocess
time
и memory
.
import resource
import subprocess
def set_memory_time(seconds):
limit_virtual_memory(seconds)
usage_start = resource.getrusage(resource.RUSAGE_CHILDREN)
print("usage_start ", usage_start)
try:
p = subprocess.check_output(
['docker exec -it cpp_compiler sh -c "g -o Test1 prog1.cpp amp;amp; ./Test1 < input.txt"'],
shell=True)
except Exception as e:
print(e)
usage_end = resource.getrusage(resource.RUSAGE_CHILDREN)
print("usage_end ", usage_end)
cpu_time = usage_end.ru_utime - usage_start.ru_utime
print("cpu_time ", cpu_time)
def limit_virtual_memory(seconds):
max_virtual_memory = 10 * 1024 * 1024 # 10 MB
usage_start = resource.getrusage(resource.RUSAGE_CHILDREN)
resource.setrlimit(resource.RLIMIT_AS, (max_virtual_memory, resource.RLIM_INFINITY))
resource.setrlimit(resource.RLIMIT_CPU, (seconds, usage_start.ru_utime seconds))
Проблема в том, что resource.setrlimit
установленный предел для основного процесса и подпроцесса использует этот предел. Когда предел превышает, это фактически также убивает процесс.
- Общая цель, которую я пытаюсь достичь здесь, заключается
subprocess.check_output(['docker exec -it cpp_compiler sh -c "g -o Test1 prog1.cpp amp;amp; ./Test1 < input.txt"']
в том, что эта строка не должна содержать больше ресурсов, чем выделено.
Есть ли способ добиться этого в python ? - Проблема, которую я пытаюсь решить здесь, заключается в том, чтобы распределять
CPU time
иmemory
ограничивать отправленный пользователемCPP
код.CPP
код в конечном итоге будет выполняться в контейнере docker для песочницы, но вы хотите ограничить используемый ресурс.
Было бы действительно полезно, если бы кто-нибудь мог предоставить информацию о проблеме и потенциальном решении или исправлении в приведенном выше коде.
Спасибо
Ответ №1:
Вы не можете ограничить использование ресурсов произвольным docker exec
процессом.
Docker использует модель клиент/сервер, поэтому при запуске docker exec
он просто отправляет запрос демону Docker. Когда вы пытаетесь setrlimit
ограничить память подпроцесса, это ограничивает только сам docker exec
процесс; но это делает запрос демону Docker, который, в свою очередь, запускает новый процесс в пространстве имен контейнера. Ни один из этих процессов не является дочерним по отношению друг к другу, и ни один из них, выходящий за рамки исходного docker exec
, не наследует эти ограничения ресурсов.
Если вместо этого вы запустите новый контейнер, вы можете использовать ограничения ресурсов Docker для нового контейнера. Они не ограничивают абсолютное количество процессорного времени, но вы, вероятно, в любом случае захотите ограничить время выполнения запущенного процесса.
Как правило, вам следует избегать использования subprocess
модуля для вызова docker
команд. Создание команд оболочки и использование их выходных данных может быть сложным делом, и если ваш код не идеален, очень легко использовать атаку с использованием оболочки, чтобы использовать docker
команду для укоренения хоста. Вместо этого используйте что-то вроде Docker SDK для Python.
Итак, если вы хотите запустить новый контейнер с фиксированным ограничением памяти и ограничить время его выполнения, вы можете сделать это с помощью чего-то вроде:
import docker
import requests
client = docker.from_env()
container = client.containers.run(
image='some/image:tag',
command=['the', 'command', 'to', 'run'],
detach=True,
mem_limit=10485760 # 10 MiB
)
try:
container.wait(timeout=30) # seconds
except requests.exceptions.ReadTimeout:
# container ran over its time allocation
container.kill()
container.wait()
print(container.logs())
container.remove()
Комментарии:
1. Спасибо @David Maze , это хорошее объяснение. На самом деле ограничения на контейнер не будут работать в нашем случае, так как мы хотим запускать несколько тестовых случаев одновременно в контейнере и хотим ограничить ограничение по времени/памяти для каждого тестового случая в контейнере, но не для контейнера. Итак, у вас есть какие-нибудь идеи, как этого добиться?
2. Контейнеры не особенно дороги и не имеют жесткой изоляции ресурсов; если вы запускаете четыре процесса в четырех контейнерах, их производительность должна быть сопоставима с их запуском в одном контейнере, а настройка будет намного проще. Я бы запустил здесь по одному контейнеру на процесс.