bigywater.tech
Docker · 43

--pids-limit:fork 炸弹被拦在哪一层

容器里的 fork 炸弹会不会拖垮整台机器?--pids-limit 到底限制什么,线程算不算?这篇在受限的容器里实测:cgroup 的 pids.max、线程计数、fork 炸弹被关在多大的范围内。

49 个线程
--pids-limit 50 的容器里,Python 能再创建的线程数(线程也占 pid)
pids.events max 35
fork 炸弹被 --pids-limit 64 挡住时,cgroup 记录的 fork 失败次数
2151 ms
被炸弹占满进程数的容器 docker stop -t 2 的用时(退出码 0)

cgroup 里的值

实测 · 本机执行输出
  不限制:pids.max=max pids.current=2
  --pids-limit 100:pids.max=100 pids.current=2
  --pids-limit -1:pids.max=max pids.current=2

--pids-limit 100 对应 pids.max = 100;不设置或设 -1 就是 max。Docker 默认不限制进程数。

线程也算

实测 · 本机执行输出
  --pids-limit 50,不停创建线程:创建了 49 个线程后失败:can't start new thread | pids.current = 50

--pids-limit 50 下创建线程,到第 50 个(含主线程)就失败了,报 can't start new thread。线程多的程序(Java、Go 的大量线程)设置过小的 pids-limit 会遇到这种错误。

fork 炸弹

实测 · 本机执行输出
  3 秒后在容器里 docker exec 读 pids.current / pids.events:退出码 0;65 | max 35
  docker stats 的 PIDS 列:64 个进程;CPU 0.00%;内存 1.391MiB / 128MiB
  docker stop -t 2:退出码 0,用时 2151 ms
  虚拟机里的其它容器和 docker 命令是否正常?docker ps 退出码 0

--pids-limit 64 把炸弹限制在 64 个进程里,cgroup 的 pids.events 记录了 35 次因上限失败的 fork;docker stats 显示 64 个进程、内存仅 1.391MiB,docker stop 和 docker ps 都正常。我同时加了 128m 内存和 1 个 CPU 的限制作为保险,所以这个实验没有单独验证「只靠 pids-limit」能保护多少资源,也没有在没有限制的容器里跑炸弹(那样会危险)。

分步演示

进程数限制
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。fork 炸弹是 sh 函数 bomb() { bomb | bomb & },只在 --pids-limit 64 --memory 128m --cpus 1 的容器里运行,3 秒后检查并停止;线程测试用 Python threading;pids.max、pids.current、pids.events 取自容器 cgroup;每种情形运行一次;实验后已删除容器
    • 没有验证:不设 pids-limit 的 fork 炸弹(不做)、Docker Desktop 虚拟机整体的 pid 上限、cgroup v1 的行为、pids-limit 与 ulimit nproc 的相互作用(nproc 见 c33)、pids.current 比上限多 1 的原因
    京ICP备2026067502号-1京公网安备11010502063487号