Skip to content

Почему в Docker-контейнере процесс приложения всегда имеет PID 1

Когда вы запускаете приложение внутри Docker-контейнера, оно почти всегда становится процессом с идентификатором PID 1 — первым и главным процессом в контейнере. Это фундаментальное поведение Docker, и понимание его причин помогает лучше управлять жизненным циклом контейнеров, обрабатывать сигналы и отлаживать проблемы. Давайте разберёмся, почему так происходит и какие последствия это имеет.


Что такое PID 1?

В операционной системе Linux каждый процесс имеет уникальный идентификатор — PID (Process ID). Процесс с PID 1 — это особенный: он является первым процессом, запущенным ядром после загрузки системы (обычно это init, systemd, upstart и т.п.). Этот процесс:

  • Не может быть убит обычными сигналами (кроме SIGKILL).
  • Отвечает за обработку "осиротевших" процессов (тех, чьи родители завершились).
  • Получает сигналы от системы (например, SIGTERM при остановке контейнера).

Как работает Docker с процессами?

Docker использует изоляцию процессов с помощью механизмов ядра Linux: namespace'ов и cgroups. Когда вы запускаете контейнер:

  1. Docker создаёт новое пространство имён процессов (PID namespace).
  2. В этом новом пространстве видны только процессы, запущенные внутри контейнера.
  3. Первый процесс, запущенный в этом namespace, получает PID 1.

Этим первым процессом становится команда, указанная в CMD или ENTRYPOINT Docker-образа.

CMD ["python", "app.py"]

Когда контейнер запускается, python app.py становится PID 1.


Почему именно PID 1?

Потому что контейнер — это изолированная среда, а не полноценная виртуальная машина. В нём нет полноценной ОС с systemd, init и другими фоновыми службами. Docker не запускает "систему" — он запускает одно приложение в изолированной среде.

Следовательно, это приложение и становится первым (и часто единственным) процессом в контейнере — PID 1.


Зачем это нужно?

  1. Жизненный цикл контейнера зависит от PID 1
    Контейнер живёт, пока жив процесс с PID 1. Как только он завершается — контейнер останавливается.

  2. Обработка сигналов
    Сигналы, отправляемые в контейнер (например, docker stop), доставляются напрямую процессу с PID 1. Если приложение не умеет корректно обрабатывать SIGTERM, контейнер может завершиться аварийно.

  3. Реапинг "осиротевших" процессов
    Если в контейнере запускаются дочерние процессы, а их родитель завершается, они становятся "осиротевшими". Обычно этим занимается init, но в контейнере такую роль выполняет PID 1. Если он не умеет "забирать" такие процессы — они превращаются в зомби-процессы.


Проблемы, связанные с PID 1

1. Некорректная обработка сигналов

Многие приложения не рассчитаны на то, чтобы быть PID 1. Они могут: - Игнорировать SIGTERM, ожидая SIGINT. - Не очищать ресурсы при завершении.

👉 Решение: Использовать tini или dumb-init как PID 1, которые проксируют сигналы.

2. Зомби-процессы

Если приложение не вызывает wait() для завершённых дочерних процессов, те превращаются в зомби.

👉 Решение: Запускать приложение через легковесный init, например:

ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "app.py"]

Или использовать флаг Docker:

docker run --init my-app

(этот флаг автоматически добавляет tini как PID 1)


Как проверить PID 1?

Внутри контейнера выполните:

ps aux

Вы увидите что-то вроде:

PID   USER   TIME  COMMAND
    1 root     0:00 python app.py

Да, это ваше приложение — PID 1.