为子进程提供CPU时间和内存

3 人关注

我一直在研究如何为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) 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中实现这一目标?

  • 我想解决的问题是试图为用户提交的 CPU time memory 代码分配限制。替换代码8】的代码最终将在docker容器上运行,以达到沙盒的目的,但希望对其使用的资源有所限制。

    如果有人能就问题和潜在的解决方案或上述代码的修正提供意见,这将是非常有帮助的。

  • python
    c++
    docker
    subprocess
    resources
    pboat
    pboat
    发布于 2021-07-18
    1 个回答
    David Maze
    David Maze
    发布于 2021-07-18
    已采纳
    0 人赞同

    你不能限制一个任意的 docker exec 进程的资源利用率。

    Docker使用的是客户/服务器模式,所以当你运行 docker exec 时,它只是向Docker守护进程发出了请求。 当你试图用 setrlimit 来限制子进程的内存时,它只是限制了 docker exec 进程本身;但它向Docker守护进程发出了请求,而后者又在容器命名空间中启动了一个新进程。 这些进程都不是彼此的子进程,而且在最初的 docker exec 之外的进程都没有继承这些资源限制。

    如果你启动一个新的容器,你可以使用 Docker's resource limits 在新的容器上。 这些并不限制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
      container.wait(timeout=30) # seconds
    except requests.exceptions.ReadTimeout:
      # container ran over its time allocation