我一直在研究如何提供Pythonsubprocess
——它自己的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 && ./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 && ./Test1 < input.txt"']
这一行的资源不应该超过分配的资源
有没有办法在python中实现这一点我在这里试图解决的问题是试图为用户提交的
CPP
代码分配CPU time
和memory
限制。CPP
代码最终将在docker容器上运行,用于沙盒目的,但希望对其使用的资源进行限制。
如果有人能在上面的代码中提供关于问题和潜在解决方案或更正的信息,那将非常有帮助。
感谢
您不能限制任意docker exec
进程的资源利用率。
Docker使用客户端/服务器模型,因此当您运行docker exec
时,它只是向Docker守护进程发出请求。当您尝试使用setrlimit
来限制子进程的内存时,它只限制docker exec
进程本身;但这会向Docker守护进程发出请求,后者反过来在容器命名空间中启动一个新进程。这些进程都不是彼此的子进程,并且超出原始docker exec
的进程都不会继承这些资源限制。
如果您启动一个新容器,则可以在新容器上使用Docker的资源限制。这些不会限制CPU时间的绝对量,但在任何情况下,您都可能希望限制已启动进程的运行时间。
通常应避免使用subprocess
模块来调用docker
命令。构造shell命令并消耗它们的输出可能很棘手,如果您的代码不完美,那么很容易使用shell注入攻击来使用docker
命令来root主机。请使用类似Docker SDK for 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()