Несколько команд в директиве Docker CMD

39

Не понимаю, что происходит, когда я пытаюсь выполнить две команды во время выполнения через директиву CMD в `Dockerfile. Я предположил, что это должно работать:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

Но это не работает. Контейнер еще не запущен. Поэтому я должен был сделать это так:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Я не понимаю Почему это? Почему первая строка не верна? Может кто-нибудь объяснить мне эти вещи "формат оболочки CMD против формата JSON и т. Д.". Простыми словами.

Сразу отмечу - то же самое было с command:директивой docker-compose.yml, как и ожидалось.

Vladan
источник

Ответы:

33

Я полагаю, что разница может быть связана с тем, что вторая команда выполняет обработку оболочки, а первая - нет. За официальной документации , есть execи shellформа, ваша первая команда является Exec формой и не, например , переменные окружения, в то время как второй один делает. Таким образом, возможно, что при использовании формы exec команда может завершиться неудачей из-за зависимости от обработки оболочки. Вы можете проверить это, запустивdocker logs CONTAINERID

Ваша вторая команда, форма оболочки, эквивалентна -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Выдержки из документации -

Примечание. В отличие от формы оболочки, форма exec не вызывает командную оболочку. Это означает, что обычная обработка оболочки не происходит. Например, CMD [ "echo", "$HOME" ]не будет делать подстановку переменных на $HOME. Если вы хотите оболочки обработки затем либо использовать форму оболочки или выполнить оболочку непосредственно, например: CMD [ "sh", "-c", "echo", "$HOME" ].

Даниил Т.
источник
Возможно, команда не выполнена из-за переменных среды. Должен ли я использовать эту execформу, так как она является предпочтительной? Почему это предпочтительнее? Или я должен использовать более простую shellформу?
Владан
Не удалось, потому что выполнение одной команды за другой является функцией оболочки. Переменными среды является красная сельдь.
Брайан,
Если вы используете несколько служб в Docker, я бы порекомендовал использовать диспетчер процессов, такой как supervisor. Таким образом, вы запускаете только супервизор в разделе CMD, и он позаботится о запуске сервисов. Вы можете проверить детали здесь - docs.docker.com/articles/using_supervisord
Daniel t.
Это точная статья, которую я только что прочитал :) Спасибо.
Владан
Я до сих пор не понимаю, зачем тебе это делать CMD [ "sh", "-c", "echo", "$HOME"]. Почему не CMD ["sh", "-c", "echo $HOME"]или, если на то пошло, CMD ["sh -c echo $HOME"]?
шестьдесят четыре бита
4

Не мешай себе. Просто создайте bash-файл «start.sh»:

#!/bin/bash

/usr/bin/command2 param1
/usr/bin/commnad1

в вашем Dockerfile сделайте:

ADD start.sh /
RUN chmod +x /start.sh

CMD ["/start.sh"]
Цифровой человек
источник
2

Синтаксис json CMDRUNи ENTRYPOINT) передает аргументы ядру напрямую как системный вызов exec. В системном вызове exec нет разделения команды на аргументы пробелами, экранирования кавычек, перенаправления ввода-вывода, подстановки переменных, передачи между командами, выполнения нескольких команд и т. Д. Системный вызов принимает только исполняемый файл и список аргументов для передачи этому исполняемому файлу, и он запускает его.

Символы, такие как $расширение переменных, ;разделение команд, (пробел) для разделения аргументов &&и ||цепочка команд, >для перенаправления вывода, |передачи между командами и т. Д., Являются функциями оболочки и нуждаются в чем-то вроде /bin/shили /bin/bashдля их интерпретации и реализации.


Если вы переключитесь на строковый синтаксис CMD, docker запустит вашу команду с оболочкой:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

В противном случае ваш второй синтаксис делает то же самое:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Обратите внимание, что я не рекомендую запускать несколько команд таким образом внутри контейнера, так как при первой ошибке команда не обрабатывается, особенно если она выполняется в фоновом режиме. Вы также оставляете оболочку, выполняющую роль pid 1 внутри контейнера, что нарушает обработку сигналов, что приводит к 10-секундной задержке и неосторожному уничтожению вашего контейнера докером. Обработка сигналов может быть уменьшена с помощью команды оболочки exec:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

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

BMitch
источник
1

Я предполагаю, что первая команда завершается неудачно, потому что в форме DOCKER CMD выполняется только первый параметр, остальные вводятся в эту команду.

Вторая форма работает, потому что все команды разделены с ";" подаются в команду sh, которая их выполняет.

devrimbaris
источник
1

Я не думаю, что вы должны ставить запятую после "начала"

вместо использования

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

пытаться

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

так как docker использует "sh -c", команда выше будет выполнена как показано ниже

/etc/init.d/nullmailer start
/etc/init.d/nullmailer /usr/sbin/php5-fpm
Ведата
источник
Синтаксис json не запускает команды с оболочкой, sh -cв этом сценарии нет.
BMitch