Не понимая, что происходит, когда я пытаюсь выполнить две команды во время выполнения через директиву 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
, как и ожидалось.
Я считаю, что разница может быть в том, что вторая команда выполняет обработку оболочки, а первая - нет. По официальная документация, есть exec
и shell
формы. Ваша первая команда - это exec
форма. В exec
форма не расширяет переменные среды, пока shell
форма делает. Возможно, что при использовании exec
form команда не работает из-за ее зависимости от обработки оболочки. Вы можете проверить это, запустив docker logs CONTAINERID
Ваша вторая команда, форма оболочки, эквивалентна -
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
Выдержки из документации -
Примечание. В отличие от формы оболочки, форма exec не вызывает командную оболочку. Это означает, что нормальной обработки оболочки не происходит. Например,
CMD [ "echo", "$HOME" ]
не будет выполнять подстановку переменных на$HOME
. Если вам нужна обработка оболочки, либо используйте форму оболочки, либо запустите оболочку напрямую, например:CMD [ "sh", "-c", "echo", "$HOME" ]
.
Не усложняйте себе жизнь. Просто создайте bash-файл "start.sh":
#!/bin/bash
/usr/bin/command2 param1
/usr/bin/command1
в вашем Dockerfile сделайте:
ADD start.sh /
RUN chmod +x /start.sh
CMD ["/start.sh"]
Синтаксис json для CMD
(и RUN
и 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.
Я предполагаю, что первая команда не работает, потому что в форме DOCKER CMD выполняется только первый параметр, остальные вводятся в эту команду.
Вторая форма работает, потому что все команды разделены знаком ";" передаются в команду sh, которая их выполняет.
Я не думаю, что вам следует ставить запятую после слова "старт"
Вместо того, чтобы использовать
CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]
пытаться
CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]
поскольку докер использует "sh -c", команда выше будет выполняться, как показано ниже
/etc/init.d/nullmailer start
/etc/init.d/nullmailer /usr/sbin/php5-fpm