bigywater.tech
Docker · 38

ulimit:容器里的文件描述符和进程数上限

--ulimit 限制的是什么?默认值是多少,soft 和 hard 有什么区别,nproc 为什么会被别的容器影响?这篇逐项实测,包括 nproc 跨容器相互影响的现象。

1048573 vs 61
默认和 nofile=64:64 时,Python 一直 open 能打开的文件个数
只能降不能升
普通用户(uid 1000)能降低 hard limit,不能再升回去
19 → 5
同 uid 的其它容器占了 14 个进程后,nproc=20 的容器还能创建的子进程数

默认值

实测 · 本机执行输出
  nofile soft=1048576 hard=1048576
  nproc soft=unlimited hard=unlimited
  core soft=0 hard=unlimited
  stack soft=8192 hard=unlimited
  memlock soft=unlimited hard=unlimited

容器默认 nofile 是 1048576(soft 和 hard),nproc 不限制。Docker Desktop 上是这个值,Linux 宿主机上取决于 dockerd 的 systemd 配置,我没有测。

nofile

实测 · 本机执行输出
  默认:打开了 1048573 个文件后失败:No file descriptors available(errno 24) | soft/hard = (1048576, 1048576)
  --ulimit nofile=64:64:打开了 61 个文件后失败:No file descriptors available(errno 24) | soft/hard = (64, 64)
  --ulimit nofile=64:1024(soft 64,hard 1024):打开了 61 个文件后失败:No file descriptors available(errno 24) | soft/hard = (64, 1024)

--ulimit nofile=64:64 后能打开的文件只剩 61 个(64 减去标准输入输出错误)。soft 才是实际生效的值;hard 是 soft 能调到的上限。

soft 与 hard

实测 · 本机执行输出
  sh: error setting limit: Invalid argument
  把 soft 调到 200(hard 128) 退出码 1
  把 soft 调到 100 退出码 0(现在 100)
  sh: error setting limit: Operation not permitted
  uid 1000 把 hard 调到 4096 退出码 1
  uid 1000 把 hard 降到 100 退出码 0
  sh: error setting limit: Operation not permitted
  再升回 128 退出码 1

soft 不能大于 hard(Invalid argument);普通用户不能把 hard 调高(Operation not permitted),只能调低,调低之后就升不回去了。

nproc 是 uid 级别的

实测 · 本机执行输出
  单个容器 --user 1000 --ulimit nproc=20:创建了 19 个子进程后失败:Resource temporarily unavailable
  另外 2 个同样 uid 1000 的容器各占了 7 个进程(1 个 sh 加 6 个 sleep),再跑同样的测试:创建了 5 个子进程后失败:Resource temporarily unavailable
  换成 uid 2000(同样 nproc=20):创建了 19 个子进程后失败:Resource temporarily unavailable
  清掉占位容器后,uid 1000 再测一次:创建了 19 个子进程后失败:Resource temporarily unavailable

nproc 限制的是同一个 uid 的进程总数,而且是在整个系统范围内数,不分容器。同 uid 1000 的另外两个容器占了 14 个进程后,新容器的 nproc=20 只剩 5 个可用;换成 uid 2000 不受影响。所以几个共用同一 uid 的容器设同一个 nproc,会互相挤占;限制容器内进程数更合适的是 --pids-limit(见后面的 pids 一篇)。

分步演示

资源限制 ulimit
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。测试程序是 python:3.12-alpine 里的小脚本:循环 open(/dev/null) 直到失败、循环创建 sleep 子进程直到失败;ulimit 值取自容器里的 sh;nproc 实验里用 2 个占位容器(--user 1000,各 7 个进程);每种情形运行一次(现象是确定性的);实验后已删除容器
    • 没有验证:Linux 宿主机的默认值、--ulimit 与 systemd 的 LimitNOFILE 的关系、core 文件、memlock、rttime;root 用户(带 CAP_SYS_RESOURCE)时 nproc 的表现;user namespace 重映射下 nproc 的统计范围
    京ICP备2026067502号-1京公网安备11010502063487号