先看现象。Kubernetes 1.26 集群里一台 4 核 8G 的 worker 跑到二十多个 Pod 后,新 Pod 卡在 ContainerCreating,kubelet 日志反复刷 too many open files,ulimit -n 显示 1024。

原因不止一个,得分开看。kubelet 由 systemd 拉起,LimitNOFILE 没配就沿用了默认的 1024。少数情况下是每个 Pod 的日志、cgroup 和网络命名空间都要占句柄,数量随 Pod 数线性上涨。

不容易想到的是,containerd 自身的句柄上限没同步放开,到限额后无法再创建 shim 进程。

还有一种情况,inotify watch 数量也受同一个 fs.file-max 约束,配置挂载多时更紧张。

上来先确认 kubelet 进程实际拿到的上限

cat /proc/$(pidof kubelet)/limits | grep -i 'open files'

临时放开当前会话的上限做验证

prlimit --pid $(pidof kubelet) --nofile=65536:65536

接着在 systemd 里写死上限并重载

mkdir -p /etc/systemd/system/kubelet.service.d && printf '[Service]\nLimitNOFILE=65536\n' > /etc/systemd/system/kubelet.service.d/limits.conf && systemctl daemon-reload

剩下的就是重启 kubelet 后复核并看 Pod 是否恢复

systemctl restart kubelet && cat /proc/$(pidof kubelet)/limits | grep -i 'open files'

这类问题以前遇到过,但这次的触发条件和上次不一样。

这类改动我都写进变更记录,过两周再出问题时能对上号。

恢复的判定其实很直接。kubelet 进程的 open files 变成 65536,ContainerCreating 的 Pod 全部转为 Running,日志里不再出现 too many open files。

改完 systemd 一定要 daemon-reload,只改 /etc/security/limits.conf 对 systemd 拉起的进程无效;containerd 也建议一起放开。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189