← Назад к вопросам

Почему PID у первого контейнера в Docker равен 1?

1.0 Junior🔥 151 комментариев
#Асинхронность и многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Почему PID у первого процесса в Docker контейнере равен 1?

Это фундаментальное свойство изоляции процессов в Linux контейнерах. PID равен 1 потому, что каждый контейнер имеет собственное пространство имён (namespace) для процессов, и первый процесс в этом пространстве всегда получает PID = 1.

Что такое PID namespace?

Docker использует Linux PID namespace для создания виртуального окружения процессов:

# На хосте при запуске контейнера видим разные PID
docker run -it ubuntu bash
# Внутри контейнера PID = 1
# На хосте видим другой PID (например, 12345)

ps aux | grep bash
# Хост видит: 12345 /bin/bash
# Контейнер видит: 1 /bin/bash

Как это работает в коде

import os
import subprocess

print(f"PID текущего процесса: {os.getpid()}")

# Внутри контейнера это выведет: 1
# На хосте это выведет: какой-то другой номер

Структура PID в контейнере

Когда запускаем контейнер с приложением на Python:

FROM python:3.11
WORKDIR /app
COPY . .
CMD ["python", "main.py"]
# Внутри контейнера процесс получает PID 1
# Это главный процесс (main entry point)
# Все остальные процессы (дочерние) получают PID 2, 3, 4 и т.д.

Почему это имеет значение

Первый процесс (PID 1) в контейнере имеет особую роль:

import signal
import time

def handle_signal(signum, frame):
    print("Получил сигнал завершения")
    exit(0)

# PID 1 должен обрабатывать сигналы правильно
signal.signal(signal.SIGTERM, handle_signal)
signal.signal(signal.SIGINT, handle_signal)

while True:
    time.sleep(1)

Проблема: "зомби" процессы

Процесс с PID 1 ответственен за сбор "зомби" процессов:

import subprocess
import os
import signal
import time

# Неправильный способ — процесс с PID 1
def bad_subprocess_handling():
    proc = subprocess.Popen(["sleep", "10"])
    # Если не дождаться, появятся зомби процессы
    # proc.wait()  # забыли вызвать!

# Правильный способ
def good_subprocess_handling():
    proc = subprocess.Popen(["sleep", "10"])
    proc.wait()  # Обязательно!

PID namespace и отражение на хосте

# На хосте:
ps aux | grep python
# root 12345 0.0 0.1 ... python main.py

# Внутри контейнера:
ps aux | grep python
# root 1 0.0 0.1 ... python main.py

# Это разные PID в разных namespace!

Изоляция процессов в Docker

Docker использует несколько mechanism для изоляции:

ls -l /proc/self/ns/
# total 0
# lrwxrwxrwx 1 root root 0 Mar 23 10:00 cgroup -> cgroup:[4026532644]
# lrwxrwxrwx 1 root root 0 Mar 23 10:00 ipc -> ipc:[4026532645]
# lrwxrwxrwx 1 root root 0 Mar 23 10:00 mnt -> mnt:[4026532646]
# lrwxrwxrwx 1 root root 0 Mar 23 10:00 net -> net:[4026532647]
# lrwxrwxrwx 1 root root 0 Mar 23 10:00 pid -> pid:[4026532648]  <-- PID namespace

Практический пример с Docker

FROM python:3.11
WORKDIR /app
COPY app.py .

RUN apt-get update && apt-get install -y procps

CMD ["python", "app.py"]
# app.py
import os
import subprocess

print(f"Мой PID: {os.getpid()}")
print("\nВсе процессы:")
subprocess.run(["ps", "aux"])
$ docker build -t myapp .
$ docker run myapp
# Мой PID: 1
# Все процессы:
# UID PID PPID ... COMMAND
# root 1 0 ... python app.py

Вывод

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