养成文字说明或者附带链接的习惯!
docker run ubuntu /bin/bash -c '(sleep 1000 &) && sleep 2000'
docker run -v /home/youmi/vhost/ag-www/test_signal.py:/test_signal.py --rm python:3.7 python test_signal.py
FROM python:3.7
CMD top
#ENTRYPOINT top
docker build -t signal . -f Dockerfile.test
docker exec signal ps aux
docker run -it --rm --name signal signal
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 12:25 pts/0 00:00:00 /bin/sh -c top
root 8 1 0 12:25 pts/0 00:00:00 top
#ENTRYPOINT top: 也是一样是/bin/sh -c top
# run的CMD如果是bash则是直接作为pid为1
docker run -it --rm --name signal signal bash -c 'top'
# run的CMD如果是sh则是sh作为pid为1
docker run -it --rm --name signal ubuntu sh -c 'top'
1 root 20 0 2384 756 692 S 0.0 0.0 0:00.02 sh
8 root 20 0 9828 3436 3012 R 0.0 0.0 0:00.00 top
当CMD指令执行时,shell 格式CMD command param1 param2
底层会调用 /bin/sh -c【command】
。如果是/bin/bash -c
就没问题?
docker run -v `pwd`/test_signal.py:/test_signal.py -v `pwd`/parent.sh:/parent.sh -v `pwd`/child.sh:/child.sh -d --rm --name signal signal sleep 10000
# 新开bash执行parent.sh,生成子进程,但即使是pid1是sleep命令,kill 掉parent,child也无法成为僵尸进程。 docker版本不一样导致的?
# 姿势不正确
docker run -i --rm -v `pwd`/test_subprocess.py:/test_subprocess.py -v `pwd`/text.txt:/text.txt --name signal signal python test_subprocess.py
docker kill signal 正常结束,无法重现
#!/usr/bin/env python3
import subprocess
import time
p = subprocess.Popen(['/bin/sleep', '1'])
time.sleep(2)
subprocess.run(['/bin/ps', '-ewl'])
FROM python:3
COPY zombie.py /
CMD ["/zombie.py"]
结果: 容器会生成僵尸进程。退出容器后,则僵尸进程会消失。
僵尸进程:子进程挂了,如果父进程不给子进程“收尸”(调用 wait/waitpid),那这个子进程就变成了僵尸进程。
UID PID PPID C STIME TTY TIME CMD
root 1 0 2 06:12 ? 00:00:00 python test_signal.py
root 9 1 0 06:12 ? 00:00:00 [sleep] <defunct>
root 10 1 0 06:12 ? 00:00:00 /bin/ps -ef
如果是本地pycharm执行。退出容器后会发现,僵尸进程的父进程变成了,pycharm的bash进程。也就是父进程接管了孤儿进程。
这时候如果想清理僵尸进程,kill不掉的,可以直接把退出父进程或者把父进程kill掉。这时候pid为1的进程接管,并且调用waitpid清理僵尸进程。
另一个测试: pid为1的 /bin/sh -c 'python x'
的进程也会产生僵尸进程。而且为什么声明dumb-init也会有僵尸进程。?
UID PID PPID C STIME TTY TIME CMD
root 1 0 1 06:18 ? 00:00:00 dumb-init python test_signal.py
root 8 1 1 06:18 ? 00:00:00 python test_signal.py
root 10 8 0 06:18 ? 00:00:00 [sleep] <defunct>
原因:僵尸进程的父进程是python进程,无法回收僵尸进程。也就是这个程序写得不对。父进程没有回收子进程导致的,而且这时候父进程还没有结束,所以即使dumb-init也还是会有僵尸进程。
这个才是正确的测试姿势。结束子进程,让子进程的子进程成为僵尸进程。被pid1进程接管。所以能很好体现dumb-init的功能。
import os
import subprocess
pid = os.fork()
if pid == 0: # child
pid2 = os.fork()
if pid2 != 0: # parent
print('The zombie pid will be: {}'.format(pid2))
else: # parent
os.waitpid(pid, 0)
subprocess.check_call(('ps', 'xawuf'))
# 下面的语句都能正确回收僵尸进程
#ENTRYPOINT ["dumb-init", "python", "test_signal.py"]
#CMD ["dumb-init", "python", "test_signal.py"]
# bash也能回收僵尸进程
#CMD python test_signal.py
# /bin/sh -c python test_signal.py
# python作为pid为1的进程,不能回收僵尸进程
CMD ["python", "test_signal.py"]
ENTRYPOINT ["python", "test_signal.py"]
结论: bash也能回收僵尸进程
但是bash进行僵尸进程的重现却不能正常重现。不知道原因是啥。
还有就是: docker run --rm python:3.7 /bin/bash -c '(sleep 10 &) && ps -ef'
结果:
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:56 ? 00:00:00 ps -ef
root 9 1 0 03:56 ? 00:00:00 sleep 10
分析: &是作为子进程。然后就是docker run的cmd命令,不会以/bin/bash为pid为1的命令。跟docker file的cmd命令不一样。