В чем разница между CMD и ENTRYPOINT в файле Docker?
В Dockerfiles есть две команды, похожие на меня: CMD
и ENTRYPOINT
. Но я предполагаю, что между ними есть (тонкая?) Разница, иначе не было бы смысла иметь две команды для одной и той же вещи.
В документации указано CMD
Основной целью CMD является предоставление значений по умолчанию для исполняемого контейнера.
и для ENTRYPOINT
:
ENTRYPOINT помогает вам сконфигурировать контейнер, который можно запустить как исполняемый файл.
Итак, какая разница между этими двумя командами?
Ответы
Ответ 1
Docker имеет точку входа по умолчанию, которая является /bin/sh -c
но не имеет команды по умолчанию.
Когда вы запускаете docker следующим образом: docker run -i -t ubuntu bash
точка входа по умолчанию - /bin/sh -c
, образ - ubuntu
а команда - bash
.
Команда запускается через точку входа. т.е. фактическая вещь, которая выполняется, это /bin/sh -c bash
. Это позволило Docker быстро реализовать RUN
, полагаясь на парсер оболочки.
Позже люди попросили уметь настроить это, поэтому были введены ENTRYPOINT
и --entrypoint
.
Все после ubuntu
в приведенном выше примере является командой и передается точке входа. При использовании инструкции CMD
все происходит так же, как если бы вы выполняли docker run -i -t ubuntu <cmd>
. <cmd>
будет параметром точки входа.
Вы также получите тот же результат, если вместо этого docker run -i -t ubuntu
команду docker run -i -t ubuntu
. Вы по-прежнему будете запускать оболочку bash в контейнере, поскольку в файле Docker для Ubuntu указан CMD по умолчанию: CMD ["bash"]
Поскольку все передается в точку входа, вы можете очень хорошо вести себя со своими изображениями. @Jiri пример хорош, он показывает, как использовать изображение в качестве "двоичного". Когда вы используете ["/bin/cat"]
качестве точки входа, а затем выполняете docker run img/etc/passwd
, вы получите ее, /etc/passwd
- это команда, которая передается точке входа, поэтому выполнение конечного результата просто /bin/cat/etc/passwd
.
Другим примером может быть любой cli в качестве точки входа. Например, если у вас есть образ redis, вместо того, чтобы запускать docker run redisimg redis -H something -u toto get key
, вы можете просто использовать ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]
и затем запустите так, чтобы получить тот же результат: docker run redisimg get key
.
Ответ 2
ENTRYPOINT
указывает команду, которая всегда будет выполняться при запуске контейнера.
CMD
указывает аргументы, которые будут переданы в ENTRYPOINT
.
Если вы хотите сделать изображение, посвященное определенной команде, вы будете использовать ENTRYPOINT ["/path/dedicated_command"]
В противном случае, если вы хотите сделать изображение для общего назначения, вы можете оставить ENTRYPOINT
неуказанным и использовать CMD ["/path/dedicated_command"]
, поскольку вы сможете переопределить этот параметр, предоставив аргументы docker run
.
Например, если ваш файл Dockerfile:
FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
Запуск изображения без какого-либо аргумента будет пинговать localhost:
$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms
Теперь запуск образа с аргументом будет ping аргументом:
$ docker run -it test google.com
PING google.com (173.194.45.70): 48 data bytes
56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
^C--- google.com ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms
Для сравнения, если ваш файл Docker:
FROM debian:wheezy
CMD ["/bin/ping", "localhost"]
Запуск изображения без какого-либо аргумента будет пинговать localhost:
$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms
Но запустив образ с аргументом, вы вызовете аргумент:
docker run -it test bash
[email protected]:/#
Подробнее см. эту статью от Брайана ДеХамера:
https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
Ответ 3
Согласно docker docs,
Команды CMD и ENTRYPOINT определяют, какая команда выполняется при запуске контейнера. Существует несколько правил, описывающих их сотрудничество.
- Dockerfile должен указывать хотя бы одну из команд
CMD
или ENTRYPOINT
. -
ENTRYPOINT
следует определять при использовании контейнера в качестве исполняемого файла. -
CMD
следует использовать как способ определения аргументов по умолчанию для команды ENTRYPOINT
или для выполнения команды ad hoc в контейнер. -
CMD
будет переопределен при запуске контейнера с альтернативными аргументами.
В приведенных ниже таблицах показано , какая команда выполняется для разных комбинаций ENTRYPOINT
/CMD
:
- No ENTRYPOINT
╔════════════════════════════╦═════════════════════════════╗
║ No CMD ║ error, not allowed ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD ["exec_cmd", "p1_cmd"] ║ exec_cmd p1_cmd ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"] ║ p1_cmd p2_cmd ║
╟────────────────────────────╫─────────────────────────────╢
║ CMD exec_cmd p1_cmd ║ /bin/sh -c exec_cmd p1_cmd ║
╚════════════════════════════╩═════════════════════════════╝
- ENTRYPOINT exec_entry p1_entry
╔════════════════════════════╦═══════════════════════════════════════════════════════════╗
║ No CMD ║ /bin/sh -c exec_entry p1_entry ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD ["exec_cmd", "p1_cmd"] ║ /bin/sh -c exec_entry p1_entry exec_cmd p1_cmd ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"] ║ /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd ║
╟────────────────────────────╫───────────────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd ║ /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd ║
╚════════════════════════════╩═══════════════════════════════════════════════════════════╝
- ENTRYPOINT ["exec_entry", "p1_entry"]
╔════════════════════════════╦═════════════════════════════════════════════════╗
║ No CMD ║ exec_entry p1_entry ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD ["exec_cmd", "p1_cmd"] ║ exec_entry p1_entry exec_cmd p1_cmd ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD ["p1_cmd", "p2_cmd"] ║ exec_entry p1_entry p1_cmd p2_cmd ║
╟────────────────────────────╫─────────────────────────────────────────────────╢
║ CMD exec_cmd p1_cmd ║ exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd ║
╚════════════════════════════╩═════════════════════════════════════════════════╝
Ответ 4
Да, это хороший вопрос. Я пока не понимаю его полностью, но:
Я понимаю, что ENTRYPOINT
является исполняемым двоичным кодом. Вы можете переопределить точку входа с помощью --entrypoint = "".
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMD - это аргумент по умолчанию для контейнера. Без точки входа аргумент по умолчанию - это команда, которая выполняется. С точкой входа cmd передается в точку входа в качестве аргумента. Вы можете эмулировать команду с точкой входа.
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
Итак, главное преимущество заключается в том, что с помощью точки входа вы можете передать аргументы (cmd) в свой контейнер. Для этого вам необходимо использовать оба параметра:
# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]
и
docker build -t=cat .
то вы можете использовать:
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default ENTRYPOINT
Ответ 5
Разница между CMD и ENTRYPOINT по интуиции:
- ENTRYPOINT: команда запускается при запуске контейнера.
- Команда CMD: для запуска при запуске контейнера или аргументов ENTRYPOINT, если это указано.
Да, это смешение.
Вы можете переопределить любой из них при запуске docker.
Разница между CMD и ENTRYPOINT на примере:
docker run -it --rm yourcontainer /bin/bash <-- /bin/bash overrides CMD
<-- /bin/bash does not override ENTRYPOINT
docker run -it --rm --entrypoint ls yourcontainer <-- overrides ENTRYPOINT with ls
docker run -it --rm --entrypoint ls yourcontainer -la <-- overrides ENTRYPOINT with ls and overrides CMD with -la
Подробнее о различиях между CMD
и ENTRYPOINT
:
Аргумент docker run
, такой как /bin/ bash, переопределяет любую команду CMD, которую мы написали в файле Docker.
ENTRYPOINT не может быть переопределен во время выполнения с помощью обычных команд, таких как docker run [args]
. args
в конце docker run [args]
приведены в качестве аргументов для ENTRYPOINT. Таким образом, мы можем создать container
, который похож на обычный двоичный файл, например ls
.
Итак, CMD может выступать в качестве параметров по умолчанию для ENTRYPOINT, а затем мы можем переопределить аргументы CMD из [args].
ENTRYPOINT можно переопределить с помощью --entrypoint
.
Ответ 6
В двух словах:
- CMD устанавливает команду и/или параметры по умолчанию, которые могут быть перезаписаны из командной строки при запуске контейнера докеров.
- Команда и параметры ENTRYPOINT не будут перезаписаны из командной строки. Вместо этого все параметры командной строки будут добавлены после параметров ENTRYPOINT.
Если вам нужна дополнительная информация или вы хотите увидеть разницу, например, есть сообщение в блоге, которое всесторонне сравнивает CMD и ENTRYPOINT с большим количеством примеров - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/
Ответ 7
Принятый ответ сказочно объясняет историю. Я нахожу, что эта таблица очень хорошо объясняет это из официального документа о том, как взаимодействовать CMD и ENTRYPOINT:
![введите описание изображения здесь]()
Ответ 8
Комментарии к функции EntryPoint в code
//ENTRYPOINT/usr/sbin/nginx.
//Задайте точку входа (по умолчанию - sh -c) в /usr/sbin/nginx.
//Принимаем CMD в качестве аргументов /usr/sbin/nginx.
Другая ссылка из документов
Вы можете использовать форму exec ENTRYPOINT для установки довольно стабильных команд и аргументов по умолчанию, а затем использовать CMD для установки дополнительных значений по умолчанию, которые с большей вероятностью будут изменены.
Пример:
FROM ubuntu:14.04.3
ENTRYPOINT ["/bin/ping"]
CMD ["localhost", "-c", "2"]
Сборка: sudo docker build -t ent_cmd.
CMD arguments are easy to override.
NO argument (sudo docker -it ent_cmd) : ping localhost
argument (sudo docker run -it ent_cmd google.com) : ping google.com
.
To override EntryPoint argument, you need to supply entrypoint
sudo docker run -it --entrypoint="/bin/bash" ent_cmdd
p.s:
В присутствии EntryPoint CMD будет содержать аргументы для подачи в EntryPoint.
В отсутствие EntryPoint CMD будет командой, которая будет запущена.
Ответ 9
В качестве примера я добавлю свой ответ 1, который поможет вам лучше понять разницу.
Предположим, мы хотим создать образ, который всегда будет запускать команду сна при запуске. Мы создадим собственное изображение и укажем новую команду:
FROM ubuntu
CMD sleep 10
Теперь мы создаем изображение:
docker build -t custom_sleep .
docker run custom_sleep
# sleeps for 10 seconds and exits
Что если мы хотим изменить количество секунд? Нам пришлось бы изменить Dockerfile
, так как значение там жестко задано, или переопределить команду, указав другую:
docker run custom_sleep sleep 20
Несмотря на то, что это работает, это не очень хорошее решение, так как у нас есть избыточная команда "сна" (целью контейнера является переход в спящий режим, поэтому явное указание команды sleep
не является хорошей практикой).
Теперь давайте попробуем использовать инструкцию ENTRYPOINT
:
FROM ubuntu
ENTRYPOINT sleep
Эта инструкция указывает программу, которая будет запускаться при запуске контейнера.
Теперь мы можем запустить:
docker run custom_sleep 20
Как насчет значения по умолчанию? Ну, вы правильно догадались:
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]
ENTRYPOINT
- это программа, которая будет запущена, и значение, переданное контейнеру, будет добавлено к нему.
ENTRYPOINT
можно переопределить, указав флаг --entrypoint
, за которым следует новая точка входа, которую вы хотите использовать.
Not mine, I once watched a tutorial that provided this example
Ответ 10
CMD:
-
CMD ["executable","param1","param2"]
: ["executable","param1","param2"]
- это первый процесс.
-
CMD command param1 param2
: /bin/sh -c CMD command param1 param2
- это первый процесс. CMD command param1 param2
разворачивается из первого процесса.
-
CMD ["param1","param2"]
: эта форма используется для предоставления аргументов по умолчанию для ENTRYPOINT
.
ENTRYPOINT (В следующем списке не рассматривается случай, когда CMD и ENTRYPOINT используются вместе):
-
ENTRYPOINT ["executable", "param1", "param2"]
: ["executable", "param1", "param2"]
- это первый процесс.
-
ENTRYPOINT command param1 param2
: /bin/sh -c command param1 param2
- это первый процесс. command param1 param2
разворачивается из первого процесса.
Как creack, сначала был разработан CMD. Затем ENTRYPOINT был разработан для большей настройки. Поскольку они не разработаны вместе, между CMD и ENTRYPOINT существует несколько перекрытий функциональности, которые часто путают людей.
Ответ 11
Большинство людей прекрасно объясняют это здесь, поэтому я не буду повторять все ответы. Но чтобы получить хорошее чувство, я бы посоветовал проверить его самостоятельно, посмотрев на процессы в контейнере.
Создайте крошечный Dockerfile формы:
FROM ubuntu:latest
CMD /bin/bash
Постройте его, запустите его с помощью docker run -it theimage
и запустите ps -eo ppid,pid,args
в контейнере. Сравните этот вывод с выводом, который вы получаете от ps при использовании:
-
docker run -it theimage bash
- Восстановление образа, но с помощью
ENTRYPOINT/bin/bash
и запуск его обоими способами - Использование
CMD ["/bin/bash"]
- ...
Таким образом, вы легко увидите разницу между всеми возможными для себя методами.
Ответ 12
Команда CMD
упомянутая в файле Dockerfile
может быть переопределена с помощью команды docker run
ENTRYPOINT
а ENTRYPOINT
нет.
Ответ 13
Это, наверное, лучшее описание, которое я нашел:
Dockerfile: ENTRYPOINT vs CMD
Короче говоря, как я понимаю: CMD
является надменным, а ENTRYPOINT
- нет. И вы можете использовать их вместе. Поэтому, если вы хотите иметь фиксированный префикс команды, но затем несколько команд, используйте ENTRYPOINT ['command', 'prefix]
, а затем CMD ['default','params']
. См. Статью.