Как превратить контейнер докера в зомби

Пару лет назад. Когда я только начал играть в докер. Я помню, что упоминались некоторые посты в блоге, если вы плохо справляетесь с процессом pid(1). Вы создадите контейнер с зомби-докером. В это время. Я решил просто следовать предложению начать, используя инструмент инициализации dumb-init. И я никогда не вижу, чтобы зомби-контейнер создавался.

Но мне все еще интересно, почему это проблема. Если я правильно помню, docker stop xxx по умолчанию отправит SIGTERM к процессу pid контейнера (1). И если процесс не может изящно остановиться в течение 10 секунд (по умолчанию). Докер заставит его убить, отправив SIGKILL Пид (1) процесс. И я также знаю, что процесс pid(1) является особенным в системе Linux. Может игнорировать SIGKILL сигнал ( ссылка). Но я думаю, что даже если PID процесса в Docker-контейнере равен 1. Это просто потому, что он использует пространства имен для охвата своих процессов. На хост-машине вы должны увидеть, что у процесса есть еще один PID. Который может быть убит ядром.

Итак, мои вопросы:

  1. Почему движок Docker не может просто уничтожить контейнер на уровне ядра хоста? Так что ни на что. Пользователь может убедиться, что контейнер уничтожен должным образом.
  2. Как я могу создать процесс зомби в 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, чтобы что-то срабатывало после процессов зомби, и вашей реальной работе контейнера не нужно было беспокоиться об этом.,

Другие вопросы по тегам