僵尸进程问题排查
鲲鹏容器发现有大量僵尸进程 ,僵尸进程自容器创建以来, 一直存在。
僵尸进程的累积会导致fd耗尽, 新进程无法启动
通过分析bash的改动点发现,bash 从4.4 版本开始做了优化。
在4.4版本之前,若执行
“/bin/bash -c /usr/sbin/ssh & /usr/sbin/crond && bash /home/admin/start_container.sh jmg.jd.com 1 jdos_imagedownload 1014993 && sleep 9999999d”, 通过fork + exec执行每个指令,父进程还是bash。
在4.4版本之后, 在执行最后一条指令时, 不会进行fork, 直接exec , 进程主体变为sleep。
已知的,如果基础镜像是centos8, euler 会有这个问题
x86的一号进程是
/bin/bash -c /usr/sbin/ssh & /usr/sbin/crond && bash /home/admin/start_container.sh jmg.jd.com 1 jdos_imagedownload 1014993 && sleep 9999999d
其中sleep 9999999d作为一号进程fork的子进程出现, 进程号是682。
基于此, 内部定位认为sleep作为1号进程时, sleep是个阻塞程序, 不具备init的职责, 因此无法回收子进程, 导致僵尸进程出现, 而x86不出现是因为1号进程不是sleep,而是
/bin/bash -c /usr/sbin/ssh & /usr/sbin/crond && bash /home/admin/start_container.sh jmg.jd.com 1 jdos_imagedownload 1014993 && sleep 9999999d
x86和鲲鹏实际上使用的都是同样的entrypoint,但是一号进程却不一样, 经定位是由于bash版本导致的差异。 x86上Centos7使用的bash版本是4.2, 鲲鹏上openEuler使用的bash版本是5.1。 通过分析bash的改动点发现, bash 从4.4 版本开始做了优化。
在4.4版本之前,若执行“/bin/bash -c /usr/sbin/ssh & /usr/sbin/crond && bash /home/admin/start_container.sh jmg.jd.com 1 jdos_imagedownload 1014993 && sleep 9999999d”, 则通过fork + exec执行每个指令, 父进程还是bash。
解决方案
微调现有的entrypoint
# 在sleep 前加这一个 `time` 命令
/bin/bash -c /usr/sbin/ssh & /usr/sbin/crond && bash /home/admin/start_container.sh jmg.jd.com 1 jdos_imagedownload 1014993 && time sleep 9999999d
【推荐】引入社区的tini作为容器镜像的1号进程
参见: https://github.com/krallin/tini
tini -- /bin/bash -c "/usr/sbin/ssh & /usr/sbin/crond && bash /home/admin/start_container.sh jmg.jd.com 1 jdos_imagedownload 1014993 && sleep 9999999d"
注: tini 需要在基础镜像里填加,linux发行版默认不带。