我已经在主机上的xinetd
docker 容器(基础映像centos:7
)内运行。rockylinux 9
xinetd
在 docker 镜像中启动服务时,它似乎挂起了。所以我使用了strace
,并发现以下输出,快速计数:
close(181189) = -1 EBADF (Bad file descriptor)
close(181190) = -1 EBADF (Bad file descriptor)
close(181191) = -1 EBADF (Bad file descriptor)
close(181192) = -1 EBADF (Bad file descriptor)
close(181193) = -1 EBADF (Bad file descriptor)
close(181194) = -1 EBADF (Bad file descriptor)
close(181195) = -1 EBADF (Bad file descriptor)
close(181196) = -1 EBADF (Bad file descriptor)
strace xinetd
在另一台主机上运行Centos 8
我看到了同样的行为。
看起来它xinetd
正在遍历所有可用的文件描述符,超过/proc/sys/fs/file-max
(如果配置了限制,它会超过该限制)直到数字用完。
这是怎么回事?为什么会出现这种行为?
2023 年 3 月更新:
对于有类似情况的人,根据下面详细的答案,你可以设置通过 docker 实现 ulimits运行容器时。这在docker compose,并且在游牧民族。不幸的是,在 k8s 中不可用。
答案1
许多传统守护进程都会这样做,作为其“守护进程化”序列的一部分,旨在避免从用户环境中继承任何东西,因为传统上(在面向 IPC 的 init 系统(如 systemd 或 Upstart)流行之前)管理员会直接从交互式会话中运行 /etc/rc.d 脚本,有时只会直接启动守护进程二进制文件 - 然后应该分叉/双分叉,重新打开 stdin/out/err,摆脱任何控制 tty,编写自己的 pid 文件,等等。
例如,旧的 /etc/rc.d/inetd 可能像这样简单:
case $1 in
start)
echo -n "Starting inetd..."
/sbin/inetd
echo "done."
[...]
但没有跨平台的方法来确定哪个文件描述符已打开。一些 Unix 具有诸如 closefrom() 之类的系统调用,其他 Unix 允许进程迭代 /proc/self/fd/[0-9],但有些 Unix 没有比从 3 一直迭代到当前 RLIMIT_NOFILE 值并盲目尝试每个可能的 FD 更好的方法。
后者就是 xinetd 所做的,假设它的 NOFILE 限制最多在 1k 到 4k 左右。(20-30 年前编写启动代码时通常就是这种情况 - 从那时起它就没有发生过太大的变化。)