Почему я не могу использовать Docker CMD несколько раз для запуска нескольких сервисов?


99

Я создал базовый образ из файла Docker с именем centos + ssh. В файле Dockerfile centos + ssh я использую CMD для запуска службы ssh.

Затем я хочу создать образ, запускающий другую службу с именем rabbitmq, Dockerfile:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

Чтобы запустить контейнер rabbitmq , запустите :

docker run -d -p 222:22 -p 4149:4149 rabbitmq

но служба ssh не работает, это означает, что CMD Dockerfile rabbitmq переопределяет CMD centos.

  1. Как CMD работает внутри образа докера?
  2. Если я хочу запустить несколько служб, как это сделать? Используете супервизора?

Ответы:


65

Хотя CMD записан в Dockerfile, на самом деле это информация времени выполнения. Так же, как EXPOSE, но в отличие от, например, RUN и ADD. Под этим я имею в виду, что вы можете переопределить его позже, в расширяемом файле Dockerfile или просто в своей команде запуска, что вы и испытываете. Всегда может быть только одна CMD.

Если вы хотите запустить несколько сервисов, я бы действительно использовал супервизор. Вы можете создать файл конфигурации супервизора для каждой службы, ДОБАВИТЬ их в каталог и запустить супервизор, supervisord -c /etc/supervisorчтобы указать на файл конфигурации супервизора, который загружает все ваши службы и выглядит так:

[supervisord]
nodaemon=true

[include]
files = /etc/supervisor/conf.d/*.conf

Если вам нужны подробности, я написал блог на эту тему здесь: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image- наследование /


Спасибо, супервизор - хорошая идея, но мне интересно, как CMD работает внутри образа докера
edwardsbean

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

119

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

Но вы можете выполнить обе команды в одной строке:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

Что вы также можете сделать, чтобы сделать ваш Dockerfile немного чище, вы можете поместить свои команды CMD в дополнительный файл:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

И такой файл:

service sshd start &
/opt/mq/sbin/rabbitmq-server start

1
спасибо, я думаю, что лучше использовать супервизор. но почему докер запускает только один CMD? что происходит внутри?
edwardsbean

1
Я не знаю, что происходит внутри. Но я думаю, что это просто так. Когда у вас есть изображение и вы запускаете в нем команду (например, с CMD), он запускает контейнер. Контейнер работает, пока выполняется команда. И как только команда завершается, контейнер также останавливается. Таким образом, каждый контейнер представляет собой одну (выполняющуюся) команду.
Thomas Uhrig

я думаю, может это из-за lcx или чего-то еще
edwardsbean

2
@ Tyguy7 .. потому что ................?
StartupGuy

1
&&Техника будет работать только с неинтерактивными службами (которые могут запускаться в фоновом режиме), в противном случае будет работать только первая.
noraj

27

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

Чтобы на самом деле ответить на ваш вопрос « почему » ... Я думаю, вам было бы полезно понять, как docker stopработает команда, и что все процессы должны завершаться аккуратно, чтобы предотвратить проблемы, когда вы пытаетесь их перезапустить (повреждение файлов и т. Д.).

Проблема: Что делать , если докер сделал запуск SSH от его команды и начал RabbitMQ из файла Докер? « Команда docker stop пытается сначала остановить работающий контейнер, отправив сигнал SIGTERM корневому процессу (PID 1) в контейнере. » Какой процесс отслеживает докеры как PID 1, который получит SIGTERM? Будет ли это SSH или Rabbit ?? «Согласно модели процессов Unix, процесс init - PID 1 - наследует все потерянные дочерние процессы и должен их получить. Большинство контейнеров Docker не имеют процесса инициализации, который делает это правильно, и в результате их контейнеры заполняются зомби-процессы с течением времени ".

Ответ: Docker просто принимает этот последний CMD как тот, который будет запущен как корневой процесс с PID 1 и получит SIGTERM от docker stop.

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

Важно отметить, что tini существует именно по этой причине, и начиная с Docker 1.13 и выше, tini официально является частью Docker, что говорит нам, что выполнение более одного процесса в Docker ДЕЙСТВИТЕЛЬНО ... поэтому даже если кто-то утверждает, что быть более опытным в отношении Docker и настаивать на том, что вы абсурдны, думая об этом, знайте, что это не так. Для этого есть вполне допустимые ситуации.

Хорошо знать:


3

Официальный докер-ответ на запуск нескольких служб в контейнере .

Он объясняет, как это можно сделать с помощью системы инициализации (systemd, sysvinit, upstart), скрипта ( CMD ./my_wrapper_script.sh) или подобного супервизора supervisord.

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


0

Чтобы понять, почему CMD предназначен для запуска только одной службы на контейнер, давайте просто поймем, что произойдет, если вторичные серверы, запущенные в одном контейнере, будут не тривиальными / вспомогательными, а «основными» (например, хранилище, связанное с приложением внешнего интерфейса). Во-первых, это нарушит несколько важных функций контейнеризации, таких как горизонтальное (автоматическое) масштабирование и перепланирование между узлами, оба из которых предполагают наличие только одного приложения (источника загрузки ЦП) на контейнер. Затем возникает проблема уязвимостей - большее количество серверов, открытых в контейнере, означает более частое исправление CVE ...

Итак, давайте признаем, что это «подталкивание» разработчиков Docker (и Kubernetes / Openshift) к передовым методам, и нам не следует изобретать обходные пути (SSH не нужен - мы docker exec / kubectl exec / oc rshразработали его замену).

  • Больше информации

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.