Почему рекомендуется запускать только один процесс в контейнере?

79

Во многих блогах и общем мнении есть поговорка, которая гласит: «один процесс на контейнер».

Почему существует это правило? Почему бы не запустить ntp, nginx, uwsgi и другие процессы в одном контейнере, в котором должны работать все процессы?

сообщения в блоге, упоминающие это правило:

Евгений
источник
Но было бы хорошо иметь очень «толстый» контейнер с десятками процессов, чтобы выполнить развертывание и работу корпоративного сервера, на котором до сих пор не может быть Docker?
Питер
@ J. Скорее всего, все будет не так. Контейнеры отличаются от виртуальных машин, есть множество мелких проблем даже для небольшого приложения - для развертывания на предприятии это будет двухлетний проект, который в первую очередь позволит запустить его в контейнере.
Евгений

Ответы:

65

Давайте на мгновение забудем архитектурные и философские аргументы высокого уровня. Хотя могут быть некоторые крайние случаи, когда несколько функций в одном контейнере могут иметь смысл, есть очень практические причины, по которым вам может потребоваться следовать принципу «одна функция на контейнер»:

  • Горизонтальное масштабирование контейнеров намного проще, если контейнер изолирован для одной функции. Нужен другой контейнер Apache? Раскрути один в другом месте. Однако, если в моем контейнере apache также есть мои базы данных, cron и другие компоненты, это усложняет ситуацию.
  • Наличие одной функции на контейнер позволяет легко повторно использовать контейнер для других проектов или целей.
  • Это также делает его более портативным и предсказуемым, чтобы разработчики могли извлекать компонент из производства для локального устранения неполадок, а не всей среды приложения.
  • Исправления / обновления (как ОС, так и приложения) могут выполняться более изолированным и контролируемым образом. Жонглирование несколькими битами и бобами в вашем контейнере не только увеличивает изображения, но и связывает эти компоненты вместе. Зачем закрывать приложения X и Y только для обновления Z?
    • Выше также справедливо для развертывания кода и откаты.
  • Разделение функций на несколько контейнеров обеспечивает большую гибкость с точки зрения безопасности и изоляции. Возможно, вы захотите (или потребуете), чтобы службы были изолированы на сетевом уровне - физически или в наложенных сетях - для поддержания сильного уровня безопасности или соблюдения таких требований, как PCI.
  • Другие более второстепенные факторы, такие как работа с stdout / stderr и отправка журналов в журнал контейнеров, сохранение контейнеров как можно более эфемерными и т. Д.

Обратите внимание, что я говорю функция, а не процесс. Этот язык устарел. Официальная докерская документация перешла от слов «один процесс» к рекомендациям «один вопрос» для каждого контейнера.

Джон
источник
1
Тем не менее, кажется, что аргумент низкого уровня против потоков подходит здесь ... web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf
jeffmcneill
Отличный, исчерпывающий ответ!
Роб Уэллс
Является ли идея о том, что вопрос на самом деле не означает «процесс» в смысле ОС - что докер и связанные с ним записи использовали другую терминологию, которая теперь прояснилась путем перехода к слову «функция»? Потому что в противном случае, хотя я признаю, что это принятый и самый высокий рейтинг ответа, я не думаю, что он отвечает на вопрос, который был задан.
Том
27

Несколько дней назад, убив контейнер с «двумя процессами», я столкнулся с некоторыми болевыми точками, из-за которых мне пришлось использовать два контейнера вместо сценария Python, который запускал два процесса:

  1. Докер хорошо распознает разбитые контейнеры. Это невозможно, когда основной процесс выглядит нормально, но какой-то другой процесс умер ужасной смертью. Конечно, вы можете контролировать свой процесс вручную, но зачем это переопределять?
  2. Журналы Docker становятся намного менее полезными, когда несколько процессов выдают свои журналы на консоль. Опять же, вы можете записать имя процесса в журналы, но Docker тоже может это сделать.
  3. Тестирование и рассуждение о контейнере становится намного сложнее.
Кристиан Зауэр
источник
Это должен быть принятый ответ.
ClintM
Согласовано. В то время как есть некоторые другие ответы с некоторыми замечательными моментами, ключевой момент - это то, как докер обращается с PID 1.
Бретт Вагнер
13

Рекомендация исходит из цели и дизайна виртуализации на уровне операционной системы.

Контейнеры были разработаны, чтобы изолировать процесс для других, предоставляя ему свое собственное пространство пользователя и файловую систему.
Это логическая эволюция, chrootкоторая заключалась в предоставлении изолированной файловой системы, следующим шагом была изоляция процессов от других, чтобы избежать перезаписи памяти и позволить использовать один и тот же ресурс (например, TCP-порт 8080) из нескольких процессов без конфликтов.

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

Запуск нескольких процессов в одном и том же контейнере требует серьезной настройки, и, в конце концов, победит цель изоляции, если вы можете запускать несколько процессов в одном и том же пользовательском пространстве, совместно используя один и тот же файловый ресурс и сетевые ресурсы, то почему бы не запустить их? на самом хосте?

Вот не полный список тяжелых настроек / ловушек, о которых я могу думать:

  • Обработка журналов

    Либо с подключенным томом, либо с чередованием на stdout, это приносит некоторое управление. Если вы используете подключенный том, у вашего контейнера должно быть свое «место» на хосте, или два одинаковых контейнера будут бороться за один и тот же ресурс. Если использовать stdout для чередования, docker logsэто может стать кошмаром для анализа, если источники не могут быть легко идентифицированы.

  • Остерегайтесь зомби-процессов

    Если один из ваших процессов потерпел крах в контейнере, супервизор не сможет очистить дочерние элементы в состоянии зомби, и хост init никогда не унаследует их. Как только вы исчерпали количество доступных pids (2 ^ 22, то есть примерно 4 миллиона), куча вещей потерпит неудачу.

  • Разделение интересов

    Если вы запускаете две разные вещи, такие как сервер apache и logstash в одном и том же контейнере, это может упростить обработку журналов, но для обновления logstash вам необходимо отключить apache. (На самом деле, вы должны использовать драйвер ведения журнала Docker) Будет ли это изящная остановка в ожидании завершения текущих сеансов или нет? Если это изящная остановка, это может занять некоторое время и стать долгим, чтобы накатить новую версию. Если вы сделаете уничтожение, вы окажете влияние на пользователей за доставку журналов, и этого следует избегать ИМХО.

Наконец, когда у вас есть несколько процессов, вы воспроизводите ОС, и в этом случае использование аппаратной виртуализации более соответствует этой потребности.

Tensibai
источник
3
Я считаю эти аргументы неубедительными. Существует огромная разница между процессом с несколькими контейнерами и выполнением на хосте. Хотя объяснение первоначального назначения контейнеров несколько уместно, на самом деле это не убедительная причина избегать многопроцессорных контейнеров. Итак, вы отвечаете «почему нет» на «почему да», что не так полезно, как могло бы быть. Может быть очень удобно запускать несколько процессов в одном контейнере - вот почему да. Почему не остается объяснить.
Ассаф Лави
1
Вы не уточнили, какую настройку вы имели в виду. И вы еще не доказали, что эта настройка более сложна, чем настройка нескольких контейнеров. Давайте рассмотрим конкретный пример: вы часто видите упакованные образы докеров, в которых супервизор выполняет некоторый основной процесс и некоторый вспомогательный процесс. Это очень легко настроить; возможно, так же просто, как разделить контейнеры. Например, приложение и журнал грузоотправителя. Таким образом, я считаю, что от вас зависит, почему это не так.
Ассаф Лави
1
Кстати, я верю, что существуют веские аргументы против многопроцессорных контейнеров, но вы не упомянули ни один из них. Но в любом случае это далеко не однозначный случай. В некоторых случаях вполне допустимо разрешить более одного процесса. Черт, некоторые очень популярные изображения порождают несколько подпроцессов - это тоже зло? Я говорю о том, что есть компромиссы, и ваш ответ рисует одностороннюю картину, в которой отсутствуют нюансы и детали.
Ассаф Лави
1
Интересно ... Похоже, у нас есть подобное (идентичное) мнение по этому Возможно, вам следует просто проигнорировать это в этом случае, потому что это было от кого-то, кто хотел заработать значок Критика ... и решил злоупотребить вашим ответом, чтобы получить этот значок ...
Pierre.Vriens
1
Я не тороплюсь с выводом ... Я просто рекомендую вам игнорировать это. Но «вы» не можете передумать из-за того, что я видел своими глазами о том, кто является анонимным отрицателем вашего ответа. Во всяком случае, время двигаться дальше ...
Pierre.Vriens
6

Как и в большинстве случаев, это не все или ничего. Руководство "один процесс на контейнер" основано на идее, что контейнеры должны служить определенной цели. Например, контейнер не должен быть одновременно веб-приложением и сервером Redis.

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

Дейв Сверски
источник
2

Процесс, который я буду называть здесь службой, 1 контейнер ~ 1 служба , если какой-либо из моих сервисов не будет выполнен, тогда я только раскручиваю соответствующий контейнер, и через несколько секунд все снова работает. Таким образом, не будет никаких зависимостей между сервисами. Рекомендуется, чтобы размер вашего контейнера не превышал 200 МБ и не превышал 500 МБ (за исключением того, что собственные контейнеры Windows превышают 2 ГБ), в противном случае он будет аналогичен виртуальной машине, но не совсем, но производительности будет достаточно. Кроме того, примите во внимание несколько параметров, таких как масштабирование, как я могу повысить устойчивость своих служб, автоматическое развертывание и т. Д.

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

mohan08p
источник