Могу ли я запустить несколько программ в контейнере Docker?

150

Я пытаюсь обернуть голову вокруг Docker с точки зрения развертывания приложения, которое предназначено для запуска на компьютерах пользователей. Мое приложение - это просто веб-приложение для колб и база данных Mongo. Обычно я бы устанавливал как на виртуальную машину, так и перенаправлял порт хоста в гостевое веб-приложение. Я хотел бы попробовать Docker, но я не уверен, как мне использовать более одной программы. Документация говорит, что может быть только ENTRYPOINT, так как я могу иметь Mongo и мое приложение для колб. Или они должны быть в отдельных контейнерах, и в таком случае, как они общаются друг с другом и как это облегчает распространение приложения?

nickponline
источник
2
Пятно на: заставляет меня задуматься, почему докер был так популярен .. (одиночный процесс ..?) - но давайте посмотрим, что нам ответят ответы ...
javadba

Ответы:

120

Может быть только одна ENTRYPOINT, но этой целью обычно является скрипт, который запускает столько программ, сколько необходимо. Вы можете дополнительно использовать, например, Supervisord или аналогичный, чтобы позаботиться о запуске нескольких служб внутри одного контейнера. Это пример docker-контейнера, выполняющего mysql, apache и wordpress в одном контейнере .

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

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

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

  1. Используйте открытые IP-порты и подключайтесь через них.
  2. Последние версии докеров поддерживают связывание .
vesako
источник
1
Похоже, что новые версии Docker теперь поддерживают контейнерные сети Docker .
jpierson
Docker теперь поддерживает запуск Supervisor, позволяя вам отделить поведение для каждого процесса, такого как autorestart = true, stdout_logfile, stderr_logfile и т. Д. Посмотрите на docs.docker.com/engine/admin/using_supervisord
Andreas Lundgren
5
Я бы определенно не рекомендовал запускать веб-приложение и mongodb в одном и том же контейнере в этом примере. В Docker есть хорошие примеры использования процессов supervisord или подобных init-процессов, но этот не является их частью. Проще использовать docker-compose, чтобы просто запустить две службы в отдельных контейнерах.
Николас ван
@ Николя-ван, почему это проще? Это потому, что если БД умирает, я могу перезапустить контейнер БД вместо того, чтобы перезапускать все это?
Brillout
Приложения на той же машине могут также взаимодействовать через доменные сокеты Unix . Высочайшая производительность гарантирована.
Скептически Джул
21

У меня было похожее требование запуска стека LAMP, Mongo DB и моих собственных сервисов

Docker - это виртуализация на основе ОС, поэтому он изолирует свой контейнер от работающего процесса, поэтому для него требуется как минимум один процесс, выполняющийся в FOREGROUND.

Таким образом, вы предоставляете свой собственный сценарий запуска в качестве точки входа, таким образом, ваш сценарий запуска становится расширенным сценарием образа Docker, в котором вы можете укладывать любое количество сервисов до тех пор, пока не будет запущен, по крайней мере, один забывчивый сервис, который слишком быстро приближается к концу

Итак, мой файл образа Docker имеет две строки ниже в самом конце:

COPY myStartupScript.sh /usr/local/myscripts/myStartupScript.sh
CMD ["/bin/bash", "/usr/local/myscripts/myStartupScript.sh"]

В моем скрипте я запускаю все MySQL, MongoDB, Tomcat и т. Д. В конце я запускаю свой Apache как основной поток.

source /etc/apache2/envvars
/usr/sbin/apache2 -DFOREGROUND

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

Надеюсь, поможет

ОБНОВЛЕНИЕ : С тех пор, как я последний раз отвечал на этот вопрос, появились новые вещи, такие как Docker compose , которые могут помочь вам запустить каждый сервис в отдельном контейнере, но связать их все вместе как зависимости между этими сервисами, попробуйте узнать больше о docker-compose и используйте его, это более элегантный способ, если ваши потребности не совпадают с ним.

Basav
источник
6

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

Обычно рекомендуется разделять проблемные области, используя одну услугу на контейнер. Эта служба может разделяться на несколько процессов (например, веб-сервер Apache запускает несколько рабочих процессов). Можно использовать несколько процессов, но чтобы получить максимальную выгоду от Docker, избегайте того, чтобы один контейнер отвечал за множество аспектов вашего общего приложения. Вы можете подключить несколько контейнеров, используя пользовательские сети и общие тома.

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

Вам определенно следует использовать docker-compose для этого и организовать несколько контейнеров с разными обязанностями.

Николаса ван
источник
2
Это комментарий, а не ответ. Пожалуйста, рассмотрите возможность добавления объяснения и / или ссылок для поддержки этой позиции. В противном случае это не поможет.
Иван Иванов
1
Это ответ в том смысле, что лучшая рекомендация, которую я могу дать в таком случае, - это использовать docker-compose. В любом случае, вы правы, что я мог бы дать больше ссылок на официальные рекомендации. Я обновлю это.
Николя-ван
Вопрос о запуске 2 процессов в одном контейнере, поэтому не заботится о лучших практиках. Я приведу вам пример: мне нужно было запустить rabbitmq внутри изображения, основанного на PhotonOS, а также процесс java ... Поэтому я использовал сценарий ввода и использовал его как ENTRYPOINT :)
Vallerious
Оригинальный вопрос не является общим вопросом о технической осуществимости запуска двух процессов в контейнере Docker. В нем указывается конкретный вариант использования, который заключается в развертывании приложения Python вместе с базой данных MongoDB. И, для этого варианта использования, лучшая рекомендация - не рекомендовать использование одного контейнера и рекомендовать использование docker-compose.
Николас ван
5

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

Мультиконтейнерная система потребовала бы некоторой дополнительной оркестровки, чтобы иметь возможность вывести все необходимые зависимости, хотя в Docker v0.6.5 + есть новое средство для помощи, встроенное в сам Docker - Linking . В случае решения с несколькими машинами, это все же то, что должно быть организовано вне среды Docker.

С двумя разными контейнерами эти две части все еще обмениваются данными по TCP / IP, но если порты не были специально заблокированы (не рекомендуется, так как вы не сможете запустить более одной копии), вам придется пропустить новый порт что база данных была представлена ​​приложению, чтобы она могла общаться с Mongo. Это опять то, с чем может помочь Linking.

Для более простой, небольшой установки, где все зависимости располагаются в одном и том же контейнере, также возможна запуск базы данных и среды выполнения Python программой, которая изначально называется ENTRYPOINT. Это может быть так же просто, как сценарий оболочки или другой контроллер процесса - Supervisord довольно популярен, и в общедоступных файлах Docker существует ряд примеров.

Алистер Булман
источник
3

Я согласен с другими ответами о том, что использование двух контейнеров предпочтительнее, но если вы настроены на создание нескольких сервисов в одном контейнере, вы можете использовать что-то вроде супервизора.

в Hipache, например, включенный Dockerfile запускает supervisord, а файл supervisord.conf указывает как на hipache, так и на redis-сервер для запуска.

Бен Шварц
источник
2

Докер предоставляет несколько примеров того, как это сделать. Облегченный вариант:

Поместите все свои команды в скрипт-обертку, вместе с информацией о тестировании и отладке. Запустите скрипт оболочки как ваш CMD. Это очень наивный пример. Во-первых, скрипт-обёртка:

#!/bin/bash

# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_first_process: $status"
  exit $status
fi

# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_second_process: $status"
  exit $status
fi

# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container will exit with an error
# if it detects that either of the processes has exited.
# Otherwise it will loop forever, waking up every 60 seconds

while /bin/true; do
  ps aux |grep my_first_process |grep -q -v grep
  PROCESS_1_STATUS=$?
  ps aux |grep my_second_process |grep -q -v grep
  PROCESS_2_STATUS=$?
  # If the greps above find anything, they will exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit -1
  fi
  sleep 60
done

Далее Dockerfile:

FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh
OzNetNerd
источник
2

Вы можете запустить 2 процесса на переднем плане, используя wait. Просто создайте скрипт bash со следующим содержимым. Например start.sh:

# runs 2 commands simultaneously:

mongod & # your first application
P1=$!
python script.py & # your second application
P2=$!
wait $P1 $P2

В вашем Dockerfile начните с

CMD bash start.sh
Сэм
источник
0

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

CMD sh -c 'mini_httpd -C /my/config -D &' \
 && ./content_computing_loop
Рафаэль
источник