Кілька команд у директиві 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, як і очікувалося.

Відповіді:


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, я рекомендую використовувати диспетчер процесів, наприклад, супервізор. Таким чином, ви запускаєте лише нагляд в розділі CMD, і він подбає про запуск послуг. Подробиці можна переглянути тут - docs.docker.com/articles/using_supervisord
Даніель 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 /

CMD ["/start.sh"]

2

Синтаксис json CMDRUNі ENTRYPOINT) передає аргументи ядра безпосередньо як exec syscall. Не відбувається відокремлення команди від аргументів пробілами, уникнення лапок, перенаправлення вводу-виводу, зміна підстановок, конфігурування між командами, виконання декількох команд тощо у системі exec syscall. Система syscall бере лише виконуваний файл для запуску та списку аргументів, які передаються цьому виконуваному файлу, і він запускає його.

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


Якщо ви перейдете на синтаксис рядка CMD, докер виконує вашу команду з оболонкою:

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

Однак безперебійне оброблення процесів у фоновому режимі вимагає переключення на якийсь менеджер багатопроцесових процесів, як нагляд, або бажано розбивати додаток на декілька контейнерів і розгортати їх із чимось на зразок докер-композиції.


1

Я думаю, що перша команда не вдається, оскільки у формі DOCKER CMD виконується лише перший параметр, решта подається в цю команду.

Друга форма працює тому, що всі команди відокремлені знаком ";" подаються в команду sh, яка їх виконує.


1

Я не думаю, що слід ставити напів коми після "запуску"

замість використання

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

Синтаксис json не запускає команди з оболонкою, sh -cу цьому сценарії немає.
BMitch
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.