容器里为什么会出现一堆 <defunct> 进程?--init 到底解决了什么、没解决什么?这篇用会故意不 wait 的 Python 程序复现僵尸进程和孤儿进程,验证 init 的作用边界,以及僵尸进程怎样把 --pids-limit 用光。
PID 1 创建 50 个子进程但不 wait:pid=1 mode=leak 僵尸进程数=50 总进程数=51 同样,加 --init(PID 1 是 docker 自带的 init):pid=7 mode=leak 僵尸进程数=50 总进程数=52
子进程退出后要由父进程 wait 才会消失。PID 1 创建了 50 个子进程但不 wait,就剩 50 个僵尸;加了 --init 后,python 变成 PID 7,仍是这些子进程的父进程,所以 50 个僵尸照旧。
孤儿进程 50 个,PID 1 是 python 且不 wait:pid=1 mode=orphan 僵尸进程数=50 总进程数=51 孤儿进程 50 个,加 --init:pid=7 mode=orphan 僵尸进程数=0 总进程数=2
子进程的父进程退出后,孤儿进程被挂到 PID 1 下面。PID 1 是不 wait 的 python 时,这些孤儿退出后变成 50 个僵尸;换成 init(--init)就一个都不剩。这就是容器里需要一个会收尸的 PID 1 的原因。
--pids-limit 40,不停创建不 wait 的子进程:第 40 次创建子进程失败:Resource temporarily unavailable | pid=1 mode=forkbomb 僵尸进程数=39 总进程数=40 --pids-limit 40,加 --init(父进程仍是 python,不是 PID 1):第 39 次创建子进程失败:Resource temporarily unavailable | pid=7 mode=forkbomb 僵尸进程数=38 总进程数=40
僵尸进程仍占着进程号。--pids-limit 40 下,不停创建不 wait 的子进程,攒到 39 个僵尸就再也创建不出子进程了(Resource temporarily unavailable)。
docker top(PID 1 是 python,3 个子进程已退出但没被 wait):
PID PPID STAT COMMAND
38280 38256 Ss python
docker exec 里用 ps 看(同一个容器):
PID PPID STAT COMMAND
1 0 S python
7 1 Z true
8 1 Z true
9 1 Z true
10 0 R psdocker top 只显示了 python,看不到 3 个已退出的子进程;进入容器用 ps 才看到 STAT 为 Z 的 true。我没有查 docker top 为什么不显示它们。