Как убить зомби-процесс (defunct process) в Linux?

«Как убить зомби-процесс (defunct process) в Linux?» — вопрос из категории Linux, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Зомби-процессы (состояние Z в ps) — это завершенные процессы, чей статус выхода не был прочитан родительским процессом. Я решаю эту проблему системно, а не просто "убивая" процессы.

Диагностика и решение:

  1. Поиск зомби-процессов:

    # Все зомби в системе
    ps aux | awk '$8 ~ /^[Zz]/ {print $0}'
    
    # Более детально с PPID (Parent Process ID)
    ps -eo pid,ppid,stat,comm | grep -w Z
    
    # Пример вывода:
    # PID   PPID  STAT COMMAND
    # 12345 67890 Z    [python] <defunct>
  2. Правильное "убийство" зомби:

    # 1. Отправить SIGCHLD родителю (запросить чтение статуса)
    kill -s SIGCHLD 67890  # PPID из примера выше
    
    # 2. Если не помогло - аккуратный restart родителя
    systemctl restart my-service  # для systemd сервисов
    
    # 3. Крайний случай - kill родителя
    kill -TERM 67890  # SIGTERM сначала
    sleep 5
    kill -KILL 67890  # SIGKILL если не сработало
  3. Профилактика в приложениях:

    # Пример для Python приложения
    import signal
    import os
    
    # Обработчик SIGCHLD
    def handle_sigchld(signum, frame):
       try:
           while True:
               # waitpid с WNOHANG не блокирует
               pid, status = os.waitpid(-1, os.WNOHANG)
               if pid == 0:
                   break
               print(f"Child {pid} exited with status {status}")
       except ChildProcessError:
           pass
    
    signal.signal(signal.SIGCHLD, handle_sigchld)
  4. Для контейнеров (Docker/Kubernetes):

    # Dockerfile - использование init процесса
    FROM alpine:latest
    
    # tini или dumb-init как PID 1
    RUN apk add --no-cache tini
    ENTRYPOINT ["/sbin/tini", "--", "python", "app.py"]
    
    # Или в docker run
    # docker run --init my-image

Важные моменты:

  • Зомби не потребляют CPU/память, только запись в таблице процессов
  • init (PID 1) автоматически убирает зомби, если их родитель умер
  • В контейнерах проблема частая, т.к. приложение часто становится PID 1 без proper signal handling
  • Мониторинг:
    # Nagios/Icinga проверка
    ZOMBIES=$(ps aux | awk '$8 ~ /^[Zz]/' | wc -l)
    if [ $ZOMBIES -gt 10 ]; then
      echo "CRITICAL: $ZOMBIES zombie processes"
      exit 2
    fi