labctl
войти регистрация

Избавиться от процессов-зомби

имя
zombie-reaper
образ
python:3.12-slim
таймаут
30с
проверка…

Задание

Избавиться от процессов-зомби

В контейнере крутится демон zombie-maker — он плодит дочерние процессы,
которые завершаются, но родитель их не wait()'ит. В итоге в таблице
процессов копятся зомби (Z в ps//proc/<pid>/stat). init: true в
docker-compose отключён (намеренно) — это и есть условие задачи.

Симптомы

$ ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
  123  122  Z  [python3] <defunct>
  125  122  Z  [python3] <defunct>
  ...

Или через /proc:

$ for p in /proc/[0-9]*; do
    s=$(awk '{print $3}' "$p/stat" 2>/dev/null)
    [ "$s" = "Z" ] && echo "$p zombie"
  done

Что нужно

Ни одного процесса в состоянии Z (zombie), чей командный путь или args
содержат python3 (маркер лабы — дочерние процессы демона).

Почему это hard

«Убить зомби» через kill -9 <pid> нельзя — зомби уже мёртв, ему нельзя
послать сигнал. Единственный способ убрать зомби — заставить родителя
сделать wait() (читать exit-статус), либо убить родителя (тогда зомби
репаются init'ом). В Docker без init: true PID 1 — это ваш процесс, и он
не всегда корректно репает детей. Решение зависит от архитектуры:

  • Если можете — почините родителя (демона), чтобы он корректно wait()'ил.
  • Если родителя трогать нельзя — перезапустите его или поставьте tini
    (легковесный init) как PID 1.
  • В реальном Docker: добавьте init: true в compose — но в этой лабе вы
    внутри контейнера, поэтому тот же эффект даёт exec tini -g -- <cmd> или
    ручной reaper.

Подсказки

  • ps -eo pid,ppid,stat,cmd — найти PPID зомби (это и есть «виновный» родитель).
  • kill <PPID> убивает родителя; ядро репает его детей (включая зомби).
  • Или: apt-get install -y tini && exec tini -g -- zombie-maker — tini
    становится PID 1 и репает всех отпрысков.
  • После решения демонстрация zombie-maker должна продолжать работать, но
    зомби не накапливать.
Подсказки

Hints: zombie-reaper

Ключевое понимание

Зомби — это уже мёртвый процесс: ядро сохранило для него exit-статус, но
родитель ещё не забрал его через wait()/waitpid(). Поэтому:

  • kill -9 <zombie-pid> не работает. Зомби нельзя «убить ещё раз».
  • Сигналы ему не доставляются — ему некуда.

Как избавиться

  1. Заставить родителя wait()'ить. Это «правильный» фикс в реальном коде —
    но родитель zombie-maker в этой лабе намеренно багом, его код можно
    править.
  2. Убить родителя — тогда зомби становятся сиротами и репаются init'ом
    (PID 1). В Docker без init: true PID 1 — это sh, который сам по себе
    reaper'ом не является, поэтому убивать родителя нужно осторожно.
  3. Поставить reaper как PID 1. tini (или dumb-init) — мини-init,
    единственная задача которого — репать зомби. В docker-compose это
    init: true, но изнутри контейнера тот же эффект даёт
    exec tini -g -- <cmd>.

Конкретные шаги в этой лабе

  • ps -eo pid,ppid,stat,cmd | grep -E ' Z ' — увидеть зомби и их PPID.
  • cat /proc/<zpid>/stat | awk '{print $1, $3, $4}' — pid, comm, state, ppid.
  • Убить zombie-maker (PPID зомби): pkill -f zombie-maker — зомби репаются.
  • Чтобы демон не вернулся (его никто не перезапускает в этой лабе) —
    достаточно просто pkill.
  • Альтернатива: apt-get install -y tini и запустить демона под tini:
    setsid tini -g -- zombie-maker &.

Последние попытки

  • Загрузка…

Разовый запуск (smoke-тест)

Атомарный цикл up → check → down. Полезно для CI; без предварительной подготовки состояния проверка завершится с ошибкой.