Как анализируются формы CMD и ENTRYPOINT exe c в файле docker? - PullRequest
1 голос
/ 17 марта 2020

Я запускаю Jupyter в Docker контейнере. Следующая форма оболочки будет работать нормально:

CMD jupyter lab --ip='0.0.0.0' --port=8888 --no-browser --allow-root /home/notebooks

Но следующая для файла docker не будет:

ENTRYPOINT ["/bin/sh", "-c"]
CMD ["jupyter", "lab", "--ip='0.0.0.0'", "--port=8888", "--no-browser", "--allow-root", "/home/notebooks"]

Ошибка:

usage: jupyter [-h] [--version] [--config-dir] [--data-dir] [--runtime-dir] [--paths] [--json] [subcommand]
jupyter: error: one of the arguments --version subcommand --config-dir --data-dir --runtime-dir --paths is required

Очевидно, что /bin/sh -c видит аргумент jupyter, но не следующие.

Интересно, что

CMD ["jupyter", "lab", "--ip='0.0.0.0'", "--port=8888", "--no-browser", "--allow-root", "/home/notebooks"]

будет работать нормально, поэтому это не может быть числом аргументов или не так ли?

Согласно https://docs.docker.com/engine/reference/builder/#cmd, форма оболочки CMD выполняется с /bin/sh -c. Так что с моей точки зрения я вижу небольшую разницу в 2 версиях. Но причина должна заключаться в том, как формы exe c оцениваются, когда ENTRYPOINT и CMD присутствуют одновременно.

1 Ответ

4 голосов
/ 17 марта 2020

На очень низком уровне команды Linux выполняются как последовательность «слов». Обычно ваша оболочка принимает командную строку, например ls -l "a directory", и разбивает ее на три слова ls -l a directory. (Обратите внимание на пробел в «каталоге»: в форме оболочки, которая должна быть заключена в кавычки, чтобы быть в одном слове.)

Команды Dockerfile CMD и ENTRYPOINTRUN) имеют две формы. В указанной вами форме, похожей на массив JSON, вы явно указываете, как слова разбиваются. Если он не выглядит как массив JSON, то все это берется как одна строка и переносится в команду sh -c.

# Explicitly spelling out the words
RUN ["ls", "-l", "a directory"]

# Asking Docker to run it via a shell
RUN ls -l 'a directory'
# The same as
RUN ["sh", "-c", "ls -l 'a directory'"]

Если вы задаете оба ENTRYPOINT и CMD два списка слов просто объединяются. Важным для вашего примера является то, что sh -c принимает следующее слово и запускает его как команду оболочки; любые оставшиеся слова могут быть использованы в качестве $0, $1, ... позиционных аргументов в этой командной строке.

Так что в вашем примере последнее, что запускается, является более или менее

ENTRYPOINT+CMD ["sh", "-c", "jupyter", ...]
# If the string "jupyter" contained "$1" it would expand to the --ip option

Другим важным следствием этого является то, что практически ENTRYPOINT не может быть форматом с чистыми строками: когда к нему добавляется CMD, вы получаете

ENTRYPOINT some command
CMD with args

ENTRYPOINT+CMD ["sh", "-c", "some command", "sh", "-c", "with args"]

и по тому же правилу все слова CMD игнорируются.

На практике вам почти никогда не требуется явно помещать объявление sh -c или SHELL в Dockerfile; вместо этого используйте команду string-form или поместите сложные логики c в сценарий оболочки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...