容器不读取/etc/security/limits.conf,而是继承dockerd进程的limitnofile值;最终nofile上限由内核fs.file-max、dockerd limitnofile、容器--ulimit三者中最严者决定,需逐层配置并验证。

容器不直接读取宿主机的 /etc/security/limits.conf,而是继承启动它的进程(即 dockerd)在创建子进程时所拥有的资源限制。换句话说,容器的 nofile 上限,本质上是 dockerd 进程自身的 LimitNOFILE 值向下传递的结果,而非来自用户级 limits 配置。
为什么改了 limits.conf 没用
很多用户尝试修改 /etc/security/limits.conf 后重启容器,却发现 ulimit -n 仍是 1024。这是因为:
- systemd 管理的服务(包括
dockerd)默认不加载 PAM 的 limits 模块,limits.conf对它无效 - 容器由
dockerdfork 出来,只能继承dockerd当前的 soft/hard nofile 值 - 即使用户 shell 的 ulimit 是 65536,只要
dockerd自身被 systemd 限制为 1024,所有容器就都卡在这个上限
关键三层限制必须对齐
一个容器最终能打开多少文件,取决于三个层级中**最严的那个**:
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
-
内核层:
fs.file-max(系统总容量),通过sysctl -w fs.file-max=1048576或写入/etc/sysctl.conf永久生效 -
进程层:
dockerd进程自身的LimitNOFILE,需在/etc/systemd/system/docker.service.d/override.conf中显式配置 -
容器层:运行时通过
--ulimit nofile=65536:65536或daemon.json的default-ulimits设置,但不能超过上一层的值
验证是否真正生效
不要只看容器里 ulimit -n,要分步确认:
- 查 dockerd 进程限制:
systemctl show docker | grep LimitNOFILE,应显示你设的数值(如 65536) - 进容器执行:
ulimit -n(软限制)和cat /proc/1/limits | grep "Max open files"(完整软硬值) - 观察实际使用量:
ls /proc/1/fd | wc -l,若持续接近上限,说明配置到位但应用可能泄漏 fd
推荐配置路径
生产环境建议按顺序操作,避免遗漏:
- 先调高内核上限:
echo 'fs.file-max = 1048576' >> /etc/sysctl.conf && sysctl -p - 再配置 dockerd 服务限制:新建
/etc/systemd/system/docker.service.d/override.conf,写入LimitNOFILE=65536 - 重载并重启:
systemctl daemon-reload && systemctl restart docker - 最后设置容器默认值:在
/etc/docker/daemon.json加"default-ulimits": {"nofile": {"soft": 65536, "hard": 65536}},再重启 dockerd










