docker,孤儿进程和僵尸进程

在docker里,使用selenium启动chrome做截图的时候,webdriver quit后,会产生很多僵尸进程。

def screenshot(url):
        current_path = os.path.join(os.path.dirname(__file__))  # 文件的暂存路径
        chrome_options = Options()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--disable-gpu')
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--disable-dev-shm-usage')
        browser_exe_path = os.path.join(current_path, "chromedriver")
        browser = webdriver.Chrome(executable_path=browser_exe_path,
                                   chrome_options=chrome_options)
        browser.get(url)
        time.sleep(5)
        size = browser.find_element_by_xpath("//main").size
        browser.set_window_size(1200, size.get("height"))
        pic_path = os.path.join(current_path, "screenshot.png")
        browser.save_screenshot(pic_path)
        browser.quit()

在调查了进程树之后,终于发现:chromedriver fork出了多个子进程和一个孙进程,而调用quit后,chrome driver正常退出,而它的子孙们变成了孤儿进程,被托管给了docker的1号进程,也就是docker的启动进程。这些孤儿进程退出后,根据孤儿进程托管的优先级,最终由1号进程托管,而1号进程没有处理(wait/waitpid),这些进程就变成了僵尸进程。

但是!!!这个1号进程和宿主机的init进程有着本质的区别,这个1号进程,并没有能力处理子进程退出的信号,所以导致僵尸进程没有人“收尸”。

僵尸进程是kill不掉的。最终,解决办法是,在1号进程加了一行代码:

signal.signal(signal.SIGCLD, signal.SIG_IGN)

在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN,这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。

参考: https://yq.aliyun.com/articles/61894

你可能感兴趣的:(docker,孤儿进程和僵尸进程)