На очень низком уровне команды Linux выполняются как последовательность «слов». Обычно ваша оболочка принимает командную строку, например ls -l "a directory"
, и разбивает ее на три слова ls
-l
a directory
. (Обратите внимание на пробел в «каталоге»: в форме оболочки, которая должна быть заключена в кавычки, чтобы быть в одном слове.)
Команды Dockerfile CMD
и ENTRYPOINT
(и RUN
) имеют две формы. В указанной вами форме, похожей на массив 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 в сценарий оболочки.