Гид по технологиям

Запуск нескольких процессов в одном контейнере Docker

• 9 min read • DevOps • Обновлено 24 Nov 2025
Многопроцессный контейнер Docker: подходы и советы
Многопроцессный контейнер Docker: подходы и советы

TL;DR

Запуск нескольких долгоживущих процессов в одном контейнере возможен, но обычно не рекомендуется. Подходы: скрипт-обёртка, флаг –init (tini), менеджеры процессов (supervisord, s6-overlay). Выберите метод по сложности приложения, требованиям к сигналам и обслуживанию. Используйте чек-листы и тесты при переходе от монолита к микросервисам.

Два процесса, запущенные в одном контейнере Docker (иллюстрация)

Быстрые ссылки

  • Идентификация проблемы

  • Обёртка нескольких процессов в одном ENTRYPOINT

  • Параметр –init для контейнера

  • Использование специализированного менеджера процессов

  • Когда следует запускать несколько процессов в контейнере?

  • Заключение

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

Идентификация проблемы

Контейнеры Docker по умолчанию предназначены для запуска одного процесса в фореграунде. Этот процесс определяется инструкциями образа ENTRYPOINT и CMD. ENTRYPOINT задаётся в образе через

Dockerfile

а CMD можно переопределить при создании контейнера. Контейнер автоматически останавливается, когда завершает работу его процесс в фореграунде.

Вы можете запустить дополнительные процессы из CMD, но контейнер будет оставаться жив только пока главный фореграунд-процесс активен. Поддерживать контейнер работающим в течение жизненного цикла двух независимых служб напрямую нельзя только с помощью механизма

ENTRYPOINT/CMD

Важно: если ваш контейнер должен корректно обрабатывать сигналы (SIGTERM, SIGINT) и предотвращать появление зомби-процессов, обычный скрипт-обёртка может этого не обеспечивать: PID 1 внутри контейнера получает специальные обязанности по реапу дочерних процессов и форвардингу сигналов.

Обёртка нескольких процессов в одном ENTRYPOINT

Самый простой метод — написать скрипт, который стартует все необходимые процессы и ожидает их завершения. Установив этот скрипт в качестве ENTRYPOINT, вы делаете его фореграунд-процессом контейнера, и он будет держать контейнер живым, пока не завершится.

#!/bin/bash

/opt/first-process &

/opt/second-process &

wait -n

exit $?

Этот пример запускает два бинарника /opt/first-process и /opt/second-process. Символ & позволяет запускать процессы в фоне, не блокируя выполнение скрипта. Команда wait -n приостанавливает исполнение до завершения одного из дочерних процессов; затем скрипт завершится с кодом этого процесса.

Плюсы обёртки:

  • Простая реализация, минимум зависимостей.
  • Хорошо подходит для пары вспомогательных процессов.

Минусы:

  • PID 1 должен правильно обрабатывать сигналы и реапить детей; простая sh/bash-обёртка этого может не делать.
  • При падении одного процесса контейнер остановится, даже если другой процесс ещё работает — иногда это желаемое поведение, но не всегда.

Рекомендация: сочетайте обёртку с --init (описано ниже) или добавьте ручную обработку сигналов и реапа в скрипт.

Параметр –init для контейнера

Одна из распространённых проблем — корректная уборка дочерних процессов (reaping zombies) и форвардинг сигналов. Docker запускает ваш CMD как процесс с PID 1, и если этот процесс не реализует логику init, зомби-процессы могут накапливаться.

Команда docker run поддерживает флаг --init, который изменяет точку входа контейнера, чтобы использовать tini в качестве PID 1. Tini — минимальная реализация init-процесса, которая запускает ваш CMD, пробрасывает сигналы и периодически очищает зомби-процессы.

Плюсы --init:

  • Лёгкий, проверенный механизм для реапа и форвардинга сигналов.
  • Не требует внесения изменений в код приложения.

Минусы:

  • Не решает задачи оркестрации процессов внутри контейнера (запуск/рестарт/зависимости).
  • Не предоставляет декларативной конфигурации сервисов.

Используйте --init, если ожидается много дочерних процессов и вы не хотите писать код для управления PID 1 вручную.

Использование специализированного менеджера процессов

Когда процессов много и их нужно надёжно администрировать (рестарт при падении, логирование, зависимости), ручные скрипты теряют смысл. В таких случаях проще поставить менеджер процессов и сделать его ENTRYPOINT.

Популярные варианты:

  • supervisord — простой, конфигурируется через /etc/supervisor/conf.d/*.conf.
  • s6-overlay — современный, лёгкий, с декларативной моделью сервисов и управляющими скриптами run/finish.

Пример конфигурации для supervisord:

[program:apache2]

command=/usr/sbin/apache2 -DFOREGROUND

[program:mysqld]

command=/usr/sbin/mysqld_safe

Фрагмент Dockerfile с установкой:

FROM ubuntu:latest

RUN apt-get install -y apache2 mysql-server supervisor

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

ENTRYPOINT [“/bin/sh”]

CMD [“/usr/bin/supervisord”]

supervisord работает непрерывно и контролирует процессы. Обратите внимание: некоторые менеджеры не останавливают контейнер при падении одного из сервисов — поведение зависит от конфигурации.

s6-overlay предлагает другой подход: каждая служба — это каталог в /etc/services.d, содержащий исполняемый скрипт run и опционально finish. Пример добавления s6-overlay в образ:

# Add s6-overlay to your image

ADD https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz /tmp

RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz

RUN printf “#!/bin/shn/usr/sbin/apache2 -DFOREGROUND” > /etc/services.d/first-service/run

RUN chmod +x /etc/services.d/first-service/run

ENTRYPOINT [“/init”]

s6-overlay автоматически запускает finish-скрипты при получении сигнала TERM и может использовать код выхода сервиса для завершения контейнера. Пример простого finish-скрипта:

#!/bin/sh

echo “$1” > /run/s6-linux-init-container-results/exitcode

Такой сценарий позволяет сервисам сообщать о коде завершения, и s6-overlay корректно передаёт его наружу.

Плюсы менеджеров:

  • Надёжное управление процессами: рестарт, логирование, зависимости.
  • Декларативность и стандартизация поведения.

Минусы:

  • Увеличение размера образа за счёт дополнительных пакетов и конфигурации.
  • Дополнительная сложность при отладке — нужно знать, как менеджер обрабатывает сигналы и коды завершения.

Практические шаблоны и примеры

  1. Простая обёртка с обработкой сигналов (рекомендуемая улучшенная версия):
#!/bin/bash

set -e

# Функция для форвардинга сигналов
_term() {
  echo "Получен TERM сигнал, пересылаем дочерним процессам"
  kill -TERM "${pids[@]}" 2>/dev/null
}

trap _term SIGTERM SIGINT

/opt/first-process &
pid1=$!
/opt/second-process &
pid2=$!

pids=( $pid1 $pid2 )

wait -n ${pids[@]}

# дождёмся полного завершения дочерних процессов
wait

exit $?

Этот скрипт демонстрирует форвардинг сигналов и хранение PID дочерних процессов в массиве для корректной отправки сигналов.

  1. Использование --init с обёрткой:
  • Команда для запуска: docker run –init my-image
  • Позволяет не писать сложный код для реапа зомби.
  1. s6-overlay: используйте, если хотите декларативную модель и корректную интеграцию с docker stop.

Когда следует запускать несколько процессов в контейнере?

Запуск нескольких процессов оправдан, если:

  • Процессы очень плотно связаны и неразделимы (например, главный бинарник + helper daemon, без которого приложение не работает).
  • Миграция на отдельные контейнеры невозможна по причинам архитектуры или ограничений окружения.
  • Вы контейнеризуете старое монолитное приложение, где процессы управляются локально.

Стоит избегать многопроцессных контейнеров в следующих случаях:

  • Если вы хотите масштабировать компоненты независимо.
  • Если вы хотите упростить отладку и мониторинг каждого компонента.
  • Если безопасность и минимальные привилегии для каждого компонента критичны.

Ментальные модели и эвристики

  • Модель “один процесс = одна ответственность”: если можно выделить процесс в отдельный сервис — делайте это.
  • Эргономика сигналов: PID 1 обязан правильно реапить дочерние процессы и форвардить сигналы — если ваш код этого не делает, используйте –init или менеджер.
  • “Fail fast”: если падение одного процесса должно привести к остановке всей единицы работы — допустим запуск нескольких процессов в одном контейнере.

Когда этот подход терпит неудачу (контрпримеры)

  • Высоконагруженные микросервисы, которые нужно масштабировать независимо — многопроцессный контейнер мешает горизонтальному масштабированию.
  • Сценарии, где процессы требуют разных уровней привилегий или изоляции по безопасности.
  • Среды с жёсткими требованиями к мониторингу и SLO: отдельные контейнеры проще подключить к метрикам и алертам.

Чек-листы по ролям

Разработчик:

  • Может ли компонент работать отдельно?
  • Есть ли необходимость в inter-process коммуникации по localhost?
  • Имеет ли основной процесс логику реапа?

Операции (Ops):

  • Менеджер процессов документирован и контролирует restart policy.
  • Тестирован shutdown через docker stop — контейнер завершает работу корректно.
  • Логи корректно собираются внешним агрегатором.

Безопасность:

  • Привилегии процессов минимальны.
  • Сегментация конфигураций и секретов по процессам реализована.
  • Нет ненужных пакетов в образе.

Критерии приёмки

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

Тест-кейсы и приёмочные проверки

  • Запуск контейнера и проверка, что оба процесса запущены.
  • Инициация падения одного процесса: проверка кода завершения контейнера или рестарта по политике менеджера.
  • Проверка поведения при SIGTERM: все процессы останавливаются корректно.
  • Нагрузочный тест: сервисы обслуживают трафик в ожидаемых пределах.

Безопасность и минимизация размера образа

  • Выбирайте лёгкие менеджеры (tini, s6), избегайте systemd в контейнерах.
  • Старайтесь минимизировать набор пакетов: каждый дополнительный пакет увеличивает поверхность атаки.
  • Ограничивайте привилегии контейнера (user, capabilities) и используйте read-only файловые системы, где возможно.

Важно: если приложение требует привилегий для одного процесса и не требует для другого, лучше разнести процессы по контейнерам, чтобы минимизировать риск.

План миграции и дорожная карта

  1. Инвентаризация: какие процессы и зависимости есть в текущем образе.
  2. Решение о границах: какие компоненты можно и нужно выделить.
  3. Выбор подхода для оставшихся много-процессных образов: обёртка + –init, supervisord или s6.
  4. Создание тестов (см. раздел тест-кейсы).
  5. Постепенное разнесение: сначала вынесите критичные компоненты в отдельные контейнеры.
  6. Мониторинг и SLO: проверьте, что метрики и алерты корректно работают после изменений.

Сравнение менеджеров (краткая матрица)

  • supervisord: прост, знаком многим, но весит больше и имеет собственный синтаксис конфигурации.
  • s6-overlay: современный, небольшой, хорошая интеграция с docker stop и finish-скриптами.
  • tini/–init: минимален, решает проблему PID 1, но не менеджер процессов.

Шаблон SOP для создания многопроцессного образа

  1. Определите список процессов и их зависимости.
  2. Выберите стратегию: обёртка, supervisord или s6.
  3. Добавьте обработку сигналов и проверку зомби-процессов.
  4. Протестируйте shutdown и restart-паттерны.
  5. Настройте логирование и мониторинг.
  6. Минимизируйте образ: удалите лишние утилиты и кеши.
  7. Документируйте поведение и коды завершения контейнера.

Краткий словарь терминов

  • PID 1: процесс в контейнере, который имеет специальную роль реапа дочерних процессов и обработки сигналов.
  • reaping: процесс очистки завершённых дочерних процессов, чтобы не оставалось зомби.
  • finish-скрипт: скрипт в s6, выполняемый при остановке сервиса для установки кода завершения.

Примерный decision flow (Mermaid)

flowchart TD
  A[Нужно ли запускать более одного процесса?] -->|Да| B{Процессы тесно связаны?}
  A -->|Нет| Z[Используйте отдельные контейнеры]
  B -->|Нет| Z
  B -->|Да| C{Требуется рестарт/сложное управление?}
  C -->|Да| D[Используйте менеджер процессов 's6/supervisord']
  C -->|Нет| E{Нужна обработка зомби/сигналов?}
  E -->|Да| F[Используйте --init + обёртка]
  E -->|Нет| G[Простая обёртка в ENTRYPOINT]

Заключение

Контейнеры по умолчанию ориентированы на один фореграунд-процесс, но запуск нескольких процессов внутри контейнера — жизнеспособная опция для узкоспециализированных сценариев. Простая обёртка подойдёт для пары тесно связанных процессов; --init решает проблемы с PID 1; менеджеры процессов (supervisord, s6) дают богатую функциональность при управлении сервисами, но добавляют сложность и вес образа.

Итоговая рекомендация: придерживайтесь одного процесса на контейнер, когда это возможно. Если вынуждены запускать несколько — выберите подходящую стратегию на основе требований по сигналам, рестартам, безопасности и масштабированию, и обязательно добавьте тесты и документацию.

Ключевые выводы

  • По умолчанию контейнеры запускают один фореграунд-процесс.
  • Обёртки, –init и менеджеры процессов — основные подходы для многопроцессных контейнеров.
  • Тестируйте обработку сигналов, отсутствие зомби и поведение при падении сервисов.
  • Разделяйте компоненты на контейнеры по возможности, чтобы упростить масштабирование и безопасность.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро