Назад | Перейти на главную страницу

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

Не понимая, что происходит, когда я пытаюсь выполнить две команды во время выполнения через директиву 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 для 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.

Я предполагаю, что первая команда не работает, потому что в форме 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