03|理解进程(2):为什么我的容器里有这么多僵尸进程?
该思维导图由 AI 生成,仅供参考
问题再现
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了容器中的僵尸进程问题,通过实际操作展示了在容器中出现僵尸进程的情况,并详细介绍了Linux进程状态的转化和限制容器中进程数目的方法。作者提出了通过pids Cgroup来限制容器中的最大进程数目,避免因创建过多进程而影响其他容器和宿主机的情况发生。文章还分析了僵尸进程的产生原因,并介绍了父进程调用wait()或者waitpid()系统调用来避免僵尸进程产生的方法。总结了僵尸进程的危害和清理方法,强调了容器中init进程必须具备清理僵尸进程的功能。文章通过代码示例和实际操作,帮助读者深入理解和解决容器中僵尸进程问题。
《容器实战高手课》,新⼈⾸单¥59
全部留言(42)
- 最新
- 精选
- 莫名C 应该不会被回收,waitpid 仅等待直接 children 的状态变化。 为什么先进入僵尸状态而不是直接消失?觉得是留给父进程一次机会,查看子进程的 PID、终止状态(退出码、终止原因,比如是信号终止还是正常退出等)、资源使用信息。如果子进程直接消失,那么父进程没有机会掌握子进程的具体终止情况。一般情况下,程序逻辑可能会依据子进程的终止情况做出进一步处理:比如 Nginx Master 进程获知 Worker 进程异常退出,则重新拉起来一个 Worker 进程。
作者回复: 谢谢 @莫名! 很好的解释!
2020-11-20586 - JianXu问题一:在Kubernetes 的情况下,是不是该节点上所有的容器都是kubelet 的子进程?不然kubelet 怎么来清理这些容器产生的僵尸进程呢? 问题二:在Docker 的场景下,容器第一个进程是用户自己写的进程,而该进程是不能保证在回收子进程资源上的质量的,所以才有Tinit 等工具,那为什么docker runtime 不默认把这样的回收功能做了呢? 问题三:Linux 为什么不设计成可以kill -9 杀死僵尸进程呢?现在把希望都寄托在父亲进程的代码质量上,而要init 回收,就得把init 到 僵尸进程之间的血缘进程全部杀死。为什么要做这样的设计呢?
作者回复: > 问题一 在kuberenetes下,kubelet还是调用 containerd/runc去启动容器的,每个容器的父进程是containerd-shim, 最终shim可以回收僵尸进程。 > 问题二 docker倒是也做了这件事。 用docker启动容器的时候 加--init参数,起来的容器就强制使用tini作为init进程了。 > 问题三 Linux进程要响应SIGKILL并且执行signal handler,只有在被进程调度到的时候才可以做。对于zombie进程,它已经是不可被调度的进程了。
2020-11-28443 - 上邪忘川总结一下这节课相关的东西 1.,父进程在创建完子进程之后就不管了,而每一个 Linux 进程在退出的时候都会进入一个僵尸状态,这时这些进入僵尸状态的进程就因为无法回收变成僵尸进程。 2.僵尸进程是无法直接被kill掉的,需要父进程调用wait()或watipid()回收。 3.清理僵尸进程的两个思路 (1)kill掉僵尸进程的父进程,此时僵尸进程会归附到init(1)进程下,而init进程一般都有正常的wait()或watipid()回收机制。 (2)利用dumb-init/tini之类的小型init服务来解决僵尸进程
作者回复: @上邪忘川, 谢谢你的总结
2020-11-2223 - 水蒸蛋老师您的意思是僵尸线程默认都不会自动关闭的,全靠父进程回收,如果产生大量僵尸进程说明父进程相关回收策略有问题是吗
作者回复: 对的
2020-11-228 - Helios僵尸进程也是进程,就是资源没有被回收,父进程还活着就不会被init回收。 补充一点 子进程推出的时候会给父进程发送个信号,如果父进程不处理这个信号就会变味僵尸进程。现在一般只会出现在c这种需要手动垃圾回收得语言了。 老师是踩过坑呢,感觉这个坑不好踩,一是因为高级语言会处理信号,就像上一节说的。还有就是啥业务场景能搞三万多进程
作者回复: @Helios, 对于容器或者说pod, 我们加了pids cgroup的限制,pids.max 对于每个容器一般就是以千为单位了,这个值还是很容易达到上限的。 我们在线上看到的大量Z进程,实际的情况要复杂一些,一个进程有多个线程,主进程处于Z状态,而还有一个线程处于D状态,但是从表象查看进程状态的时候,看到都是<defunct>进程了(Z)。由于有了D的线程在里面,这时候waitpid(), 任何信号对这些进程都无效了。 这一讲,我是把Z进程的概念单独说了一下,对于D进程,它会引起其他的一些现象,我会在后面讲到。
2020-11-2037 - Delia我是一个Docker新手,请教一下老师,经常看到一些容器僵尸,状态栏显示:Exited (2) 10 days ago,Exited (1) 10 days ago,Exited (100) 10 days ago等等,这些容器为啥不能被回收呢?目前只能docker rm清理掉。
作者回复: docker 自己没有自动清理的功能。如果是kubernetes/kubelet是会做清理。
2020-11-2535 - 朱雯最后我作为一个运维工程师,我还是不知道怎么处理僵死进程,第一我可能不能直接杀死他们的父进程,因为可能有用,第二,我无法kill掉他们,第三我无法修改代码,代码本身对我是黑盒子。
作者回复: 我觉得刚才 @上邪忘川的回复挺好的 3.清理僵尸进程的两个思路 (1)kill掉僵尸进程的父进程,此时僵尸进程会归附到init(1)进程下,而init进程一般都有正常的wait()或watipid()回收机制。 (2)利用dumb-init/tini之类的小型init服务来解决僵尸进程
2020-11-2285 - nuczzzk8s+kata集群会有这个问题吗?感觉kata做了内核隔离,容器里的僵尸进程应该影响不到宿主机了
作者回复: kata是基于VM的,它里面的僵尸进程不会影响到宿主机。
2021-01-124 - 1900老师你好 关于设置容器的Cgroup 中 pids.max配置 ,是跟业务进程一起运行在容器中然后修改当前的容器配置,是否还有其他优雅的方式呢 ?
作者回复: 对容器设置pids Cgroup限制,一般需要容器云平台来做,在启动容器的时候就自动的设置好,类似cpu/memory Cgroup的设置。 像Kubernetes的类似这么做, https://github.com/kubernetes/kubernetes/commit/ecd6361ff0e8421332a50e55fcba17b823d5d338
2020-11-204 - 争光 Alan老师,我最近发现ulimit也会限制进程数量,这两个有什么区别吗?在容器内具体是哪个在生效?
作者回复: ulimit对于shell session中的总进程数量做限制,pids cgroup对于控制块中的cgroup.procs/tasks 中的进程数目做限制。都会起效,看哪个先达到限制值。
2021-03-1732