创建一个 python 程序
#!/usr/bin/env python3
import subprocess
import time
import os
print(os.getpid())
p = subprocess.Popen(['/bin/sleep', '1'])
time.sleep(1000000)
在这个程序中,主进程会启动一个 sleep 子进程,这个 sleep 在1秒之后就执行结束了,此时,它会进入等待被回收的状态
但是主进程此时进入了 sleep(1000000),在阻塞过程中并没有对子进程进行回收,所以并没有对 子进程 进行回收
6701 主进程,6702 子进程变成了僵尸
也就是说只要满足两个条件就可以轻松的获得一个僵尸进程
- 父进程阻塞(sleep)
- 子进程结束执行,等待回收
根据以上两种条件,我们尝试一下docker的情况
- 我们先创建一个 sleep 的 ubuntu 容器,这个容器的 1号进程是一个 阻塞进程,也就是说它不会回收任何子进程
- 我们使用 bash创建了几个 bash 进程
接下来,让我们 kill 27号进程,这样30号进程的父进程就会变成 1号进程(也就是sleep进程)
此时,30号进程的父进程就变成了对它不管不顾的 sleep 进程
因为 27号进程已经被 24号进程回收了,所以宿主机中没有 僵尸进程
我们kill掉 没人管的 30号进程
这样我们就成功的创建了一个僵尸进程
容器内 PID 30,宿主机上 PID 7132
把容器停掉的话,僵尸进程会被宿主机回收
综上所述,当
- Docker容器的主进程因为某种原因处于阻塞状态
- 主进程创建了一些子进程
- 这些 子进程 的 父进程一旦变为 阻塞中的容器主进程 ,它们在运行结束后,将成为无法被回收的 僵尸进程