В чем разница между CMD и ENTRYPOINT в Dockerfile?


1701

В Dockerfiles есть две команды, которые похожи на меня: CMDи ENTRYPOINT. Но я думаю, что между ними есть (тонкая?) Разница - иначе было бы бессмысленно иметь две команды для одной и той же вещи.

Документация заявляет для CMD

Основная цель CMD - предоставить значения по умолчанию для исполняющего контейнера.

и для ENTRYPOINT:

ENTRYPOINT помогает вам настроить контейнер, который вы можете запускать как исполняемый файл.

Итак, в чем разница между этими двумя командами?


12
В этом блоге есть хорошее описание различий и того, как их можно использовать вместе: crosbymichael.com/dockerfile-best-practices.html .
SLM

2
^ это! Спасибо @slm. Вот еще одна очень похожая ссылка, которая может быть немного более актуальной: docs.docker.com/reference/builder/#entrypoint
Адам Монсен

5
Как сбивает с толку, как разница между ADDиCOPY
Raedwald

1
Эта ссылка обеспечивает разницу между RUN, CMD и ENTRYPOINT: goinbigdata.com/docker-run-vs-cmd-vs-entrypoint
prafi

1
@JaimeHablutzel Фраза: сделай себе одолжение
Джонатан Комар

Ответы:


1738

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. Вы по-прежнему запускаете оболочку 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.


3
Не за что. ENTRYPOINT устанавливает метаданные, которые могут (но могут быть переопределены) во время выполнения, поэтому, если вы ничего не измените, после запуска вашего контейнера, результат будет таким же, однако RUN будет отображаться во время сборки и независимо от того, что вы делать во время выполнения, это будет здесь.
creack

8
По умолчанию нет ENTRYPOINT; используется ли оболочка, зависит от используемой формы CMDкоманды ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade

19
Спасибо за это, исторический контекст очень помогает, так как я изо всех сил пытался вспомнить, казалось бы, загадочные правила о том, что переопределяется, что добавляется и т. Д. Полезный момент для авторов технической документации повсюду: помогите читателю построить интеллектуальную модель системы, не просто перечисляйте факты и сценарии :-)
ashirley

84
Это невероятный ответ. Я думаю , что Docker документация должна добавить это под раздел под названием CMDпротив ENTRYPOINT.
Tarik

5
@ Webman Нет. Это две разные инструкции. Если они оба существуют, CMD будет рассматриваться как параметры ENTRYPOINT.
Light.G

628

ENTRYPOINT Задает команду , которая всегда будет выполняться при запуске контейнера.

В CMDЗадает аргументы , которые будут подаваться вENTRYPOINT .

Если вы хотите сделать изображение, посвященное определенной команде, вы будете использовать ENTRYPOINT ["/path/dedicated_command"]

В противном случае, если вы хотите создать изображение общего назначения, вы можете оставить его без ENTRYPOINTуказания и использовать, CMD ["/path/dedicated_command"]поскольку вы сможете переопределить настройку, предоставив аргументы дляdocker run .

Например, если ваш Dockerfile:

FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["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

Теперь, запуск изображения с аргументом будет проверять аргумент:

$ 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

Для сравнения, если ваш Dockerfile:

FROM debian:wheezy
CMD ["/bin/ping", "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
root@e8bb7249b843:/#

См. Эту статью от Брайана ДеХамера для более подробной информации: https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/


219
The ENTRYPOINT specifies a command that will always be executed when the container starts. The CMD specifies arguments that will be fed to the ENTRYPOINT.хорошее краткое изложение.
Цзинго Яо

1
ENTRYPOINT также можно переопределить с помощью флага --entrypoint. например, для запуска Docker --it --entrypoint bash test
seenimurugan

2
Мне нравятся ваши примеры, это действительно полезно!
Чау

2
@ Цзинго Яо: Что, если CMD содержит такую ​​команду, как - CMD ["nginx", "- g", "daemon", "off"]? Будет ли он прикован цепью?
KMC

@KMC CMD является аргументом по умолчанию для ENTRYPOINT, вы переопределяете его, передавая новый аргумент при запуске изображения.
MGP

237

Согласно докерской документации ,

Инструкции CMD и ENTRYPOINT определяют, какая команда выполняется при запуске контейнера. Есть несколько правил, которые описывают их сотрудничество.

  1. В Dockerfile должна быть указана хотя бы одна из команд CMDили ENTRYPOINT.
  2. ENTRYPOINT должен быть определен при использовании контейнера в качестве исполняемого файла.
  3. CMDдолжен использоваться как способ определения аргументов по умолчанию для ENTRYPOINTкоманды или для выполнения специальной команды в контейнере.
  4. 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   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD [“p1_cmd”, “p2_cmd”]   ║ /bin/sh -c exec_entry p1_entry   ║
╟────────────────────────────╫──────────────────────────────────╢
║ CMD exec_cmd p1_cmd        ║ /bin/sh -c exec_entry p1_entry   ║
╚════════════════════════════╩══════════════════════════════════╝

- 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  ║
╚════════════════════════════╩═════════════════════════════════════════════════╝

Что такое px_cmd и exec_entry? Что означает, когда они находятся в одной строке исполнения? Они передаются в качестве аргумента друг другу? Даже когда /bin/sh -cучаствует?
Danielo515

1
@ Danielo515 И «px_cmd», и «exec_entry» здесь просто фиктивные строки. Вы можете просто заметить, что /bin/sh -cон будет добавлен в CMD в качестве префикса, а CMD записан в исполняемом синтаксисе (не в синтаксисе списка).
Light.G

1
@royki Если пользователь указывает аргументы для запуска Docker, он переопределяет значение по умолчанию, указанное в CMD.
Донрондадон

2
ENTRYPOINT exec_entry p1_entбыл неправильно объяснен. Форма оболочки не позволяет использовать любые аргументы командной строки CMD или запуска - docs.docker.com/engine/reference/builder/#entrypoint
Mariusz Miesiak

1
@MariuszMiesiak теперь обновлен. Спасибо за ваш отзыв.
Рафаф Тахсин

170

Да, это хороший вопрос. Я еще не совсем понимаю, но:

Я понимаю, 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

@Blauhirn В вашем случае вы должны добавить аргументы к CMD в синтаксисе списка и убедиться, что точка входа, которую вы указали, может анализировать ваши аргументы в CMD. Обычно я добавляю аргумент -h к точке входа. Затем я могу выполнить, docker run image_name -hчтобы показать некоторую справочную информацию об этом изображении.
Light.G

1
Это самый простой и понятный ответ.
Эрик Ван

44

Разница между CMD и ENTRYPOINT по интуиции :

  • ENTRYPOINT: команда для запуска при запуске контейнера.
  • CMD: команда для запуска при запуске контейнера или аргументы для ENTRYPOINT, если указано.

Да, это смешивается.

Вы можете переопределить любой из них при запуске Docker Run.

Разница между 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, которую мы написали в Dockerfile.

ENTRYPOINT нельзя переопределить во время выполнения с помощью обычных команд, таких как docker run [args]. В argsконце docker run [args]указываются аргументы ENTRYPOINT. Таким образом, мы можем создать a containerкак обычный двоичный файл, такой как ls.

Таким образом, CMD может выступать в качестве параметров по умолчанию для ENTRYPOINT, а затем мы можем переопределить аргументы CMD из [args].

ENTRYPOINT можно переопределить с помощью --entrypoint.


38

В двух словах:

  • CMD устанавливает команду и / или параметры по умолчанию, которые могут быть перезаписаны из командной строки при запуске Docker-контейнера.
  • Команда и параметры ENTRYPOINT не будут перезаписаны из командной строки. Вместо этого все параметры командной строки будут добавлены после параметров ENTRYPOINT.

Если вам нужно больше деталей или вы хотите увидеть разницу на примере, есть блог, в котором подробно сравниваются CMD и ENTRYPOINT с множеством примеров - http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/


21

Я добавлю свой ответ в качестве примера 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флаг, а затем новой точкой входа вы хотите использовать.

Не мое, я когда-то смотрел учебник, который предоставил этот пример


1
Вот ссылка на учебник: youtu.be/OYbEWUbmk90 . Это может быть полезно для будущих пользователей.
ChiPlusPlus


7

Комментарии к функции EntryPoint в коде

// 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 -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

ps: при наличии EntryPoint CMD будет содержать аргументы для подачи в EntryPoint. В отсутствие EntryPoint CMD будет командой, которая будет выполняться.


3

CMDКоманда, упомянутая внутри Dockerfileфайла, может быть переопределена с помощью docker runкоманды, но ENTRYPOINTне может быть.


4
docker run --helpКоманда говорит иначе:--entrypoint string Overwrite the default ENTRYPOINT of the image
Iomv

3

Я прочитал все ответы и хочу подвести итог для лучшего понимания на первый взгляд, например:

Во-первых, вся команда, выполняемая в контейнере, состоит из двух частей: команды и аргументов.

  • ENTRYPOINT определяет исполняемый файл, вызываемый при запуске контейнера (для команды)

  • CMD определяет аргументы, которые передаются в ENTRYPOINT (для аргументов)

В книге Kubernetes In Action отмечается важная заметка об этом. (глава 7)

Хотя вы можете использовать инструкцию CMD, чтобы указать команду, которую вы хотите выполнить при запуске образа, правильный путь - это выполнить инструкцию ENTRYPOINT и указать CMD, только если вы хотите определить аргументы по умолчанию.

Вы также можете прочитать эту статью для лучшего объяснения в простой форме


2

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разветвляется с первого процесса.

Как сказал Крек , CMD был разработан первым. Затем была разработана ENTRYPOINT для дополнительной настройки. Поскольку они не предназначены для совместной работы, между CMD и ENTRYPOINT существуют некоторые функциональные совпадения, которые часто путают людей.


2

Большинство людей прекрасно объясняют это здесь, поэтому я не буду повторять все ответы. Но чтобы получить хорошее чувство, я бы предложил проверить его самостоятельно, посмотрев на процессы в контейнере.

Создайте крошечный 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"]
  • ...

Таким образом, вы легко увидите различия между всеми возможными для себя методами.


0

Официальная документация лучших практик Dockerfile объясняет различия. Лучшие практики Dockerfile

CMD:

Инструкция CMD должна использоваться для запуска программного обеспечения, содержащегося в вашем образе, вместе с любыми аргументами. CMD почти всегда следует использовать в форме CMD ["executable", "param1", "param2"…]. Таким образом, если изображение предназначено для службы, такой как Apache и Rails, вы должны выполнить что-то вроде CMD ["apache2","-DFOREGROUND"]. Действительно, эта форма инструкции рекомендуется для любого сервисного изображения.

ТОЧКА ВХОДА:

Лучшее использование для ENTRYPOINT - установить основную команду изображения, позволяя запускать этот образ, как если бы это была эта команда (а затем использовать CMD в качестве флагов по умолчанию).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.