Как превратить контейнер докера в зомби
Пару лет назад. Когда я только начал играть в докер. Я помню, что упоминались некоторые посты в блоге, если вы плохо справляетесь с процессом pid(1). Вы создадите контейнер с зомби-докером. В это время. Я решил просто следовать предложению начать, используя инструмент инициализации dumb-init. И я никогда не вижу, чтобы зомби-контейнер создавался.
Но мне все еще интересно, почему это проблема. Если я правильно помню, docker stop xxx
по умолчанию отправит SIGTERM
к процессу pid контейнера (1). И если процесс не может изящно остановиться в течение 10 секунд (по умолчанию). Докер заставит его убить, отправив SIGKILL
Пид (1) процесс. И я также знаю, что процесс pid(1) является особенным в системе Linux. Может игнорировать SIGKILL
сигнал ( ссылка). Но я думаю, что даже если PID процесса в Docker-контейнере равен 1. Это просто потому, что он использует пространства имен для охвата своих процессов. На хост-машине вы должны увидеть, что у процесса есть еще один PID. Который может быть убит ядром.
Итак, мои вопросы:
- Почему движок Docker не может просто уничтожить контейнер на уровне ядра хоста? Так что ни на что. Пользователь может убедиться, что контейнер уничтожен должным образом.
- Как я могу создать процесс зомби в Docker-контейнере? (Если кто-то может поделиться Gist будет здорово!)
1 ответ
Не зомби- контейнеры, а зомби- процессы. Напиши это zombie.py
:
#!/usr/bin/env python3
import subprocess
import time
p = subprocess.Popen(['/bin/sleep', '1'])
time.sleep(2)
subprocess.run(['/bin/ps', '-ewl'])
Напиши это Dockerfile
:
FROM python:3
COPY zombie.py /
CMD ["/zombie.py"]
Постройте и запустите его:
chmod +x zombie.py
docker build -t zombie .
docker run --rm zombie
Что здесь происходит, /bin/sleep
Команда выполняется до исполнения. Родительский процесс должен использовать wait
вызов, чтобы убрать после этого, но это не так, когда он работает ps
, вы увидите "Z" процесс зомби.
Но подождите, это еще не все! Скажем, ваш процесс тщательно очищается после себя. В этом конкретном примере subprocess.run()
включает в себя необходимые wait
позвоните, например, и вы можете изменить Popen
позвонить run
, Если этот подпроцесс запускает другой подпроцесс и выходит (или падает), не ожидая его, процесс init с pid 1 становится новым родительским процессом зомби. (Он работал таким образом в течение 40 лет.) Однако в контейнере Docker основной контейнерный процесс выполняется с pid 1, и, если он не ожидает "дополнительных" дочерних процессов, вы можете получить устаревшие процессы-зомби на весь срок службы контейнер.
Это иногда приводит к предположению, что контейнер Docker всегда должен запускать своего рода "настоящий" процесс инициализации, возможно, такой же минимальный, как tini, чтобы что-то срабатывало после процессов зомби, и вашей реальной работе контейнера не нужно было беспокоиться об этом.,