Как превратить контейнер докера в зомби - PullRequest
0 голосов
/ 04 июля 2018

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

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

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

  1. Почему движок Docker не может просто уничтожить контейнер на уровне ядра хоста? Так что ни на что. Пользователь может убедиться, что контейнер уничтожен должным образом.
  2. Как я могу создать зомби-процесс в докере? (Если кто-то может поделиться Gist будет здорово!)

1 Ответ

0 голосов
/ 04 июля 2018

Не зомби контейнеры , а зомби процессы . Напишите это 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 , чтобы что-то поднималось после процессов зомби и вашего фактического контейнера. работа не должна волноваться об этом.

...