В чем разница между 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/

Ответ 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']. См. Статью.