Skip to content

Latest commit

 

History

History
159 lines (112 loc) · 5.22 KB

优雅退出例子.md

File metadata and controls

159 lines (112 loc) · 5.22 KB

测试例子

养成文字说明或者附带链接的习惯!

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

测试cmd的shell格式

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子进程

但是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命令不一样。