Яка різниця між CMD та ENTRYPOINT у Dockerfile?


1697

У 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

Просто зауважте, що CMDі ENTRYPOINTобидва мають різні форми для запису, виконання та форми оболонки . Тож зробіть собі прихильність і зрозумійте тонкі відмінності в поведінці залежно від форми, що використовується. Потім прочитайте docs.docker.com/engine/reference/builder/… .
Хайме Хаблуцель

Відповіді:


1735

Докер має точку входу за замовчуванням, яка є, /bin/sh -cале не має команди за замовчуванням.

Якщо ви запускаєте докер так: 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 оболонку в контейнері, оскільки Dockerfile ubuntu вказав CMD за замовчуванням:CMD ["bash"]

Оскільки все передається до точки входу, ви можете мати дуже приємну поведінку зі своїх зображень. Приклад @Jiri хороший, він показує, як використовувати зображення як "двійкове". Якщо ви використовуєте ["/bin/cat"]як вхідну точку, а потім виконуєте docker run img /etc/passwd, ви отримуєте це, /etc/passwdце команда і передається в точку входу, тому виконання кінцевого результату просто /bin/cat /etc/passwd.

Іншим прикладом може бути будь-який кліп в якості точки входу. Наприклад, якщо у вас є 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 буде виконано під час створення та незалежно від того, що ви робити під час виконання, це буде тут.
скрип

8
За замовчуванням немає ENTRYPOINT; чи використовується оболонка, залежить від використовуваної форми CMDкоманди ( docs.docker.com/engine/reference/builder/#cmd ).
Blaisorblade

19
Дякую за це, історичний контекст дуже допомагає, оскільки я намагався згадати начебто таємні правила щодо того, що перекрито, а що додано і т. Д. Корисний момент для письменників технічної документації скрізь: допомогти читачеві побудувати ментальну модель системи, не просто перераховуйте факти та сценарії :-)
ashirley

84
Це казкова відповідь. Я думаю , що Docker документація повинна додати це під розділ під назвою CMDпроти ENTRYPOINT.
Тарік

5
@Webman Ні. Це дві різні інструкції. Якщо вони обоє існують, CMD трактуватиметься як параметри ENTRYPOINT.
Світло.Г

627

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


218
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.є хорошим точним резюме.
Jingguo Yao

1
ENTRYPOINT також можна змінити, використовуючи прапор --entrypoint. наприклад, docker run -it --entrypoint bash test
sawimurugan

2
Мені подобаються ваші приклади, це дуже корисно!
Чау Джан

2
@Jingguo Yao: Що робити, якщо CMD містить таку команду, як - CMD ["nginx", "- g", "демон", "off"]? Невже це буде прикуто?
KMC

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

237

Згідно з документами docker ,

І інструкції CMD, і ENTRYPOINT визначають, яка команда виконується під час запуску контейнера. Є кілька правил, які описують їхню співпрацю.

  1. Dockerfile повинен вказати принаймні одну з команд CMDабо ENTRYPOINT.
  2. ENTRYPOINT слід визначити при використанні контейнера як виконуваного файлу.
  3. CMDслід використовувати як спосіб визначення аргументів за замовчуванням для ENTRYPOINTкоманди або для виконання ad-hoc команди в контейнері.
  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 записаний у виконуваний синтаксис (не перелічений синтаксис).
Світло.Г

1
@royki Якщо користувач вказує аргументи для запуску докера, він замінить типовий параметр, визначений у CMD.
donrondadon

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щоб показати деяку довідкову інформацію про це зображення.
Світло.Г

1
Це найпростіша і зрозуміла відповідь.
Ерік Ван

44

Різниця між CMD та ENTRYPOINT за інтуїцією :

  • ENTRYPOINT: команда для запуску при запуску контейнера.
  • CMD: команда, яку потрібно запустити, коли контейнер запускається, або аргументи ENTRYPOINT, якщо зазначено.

Так, це змішування.

Ви можете змінити будь-яку з них під час запуску докерного запуску.

Різниця між 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. Таким чином ми можемо створити такий, containerякий є як звичайний бінарний файл, наприклад ls.

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

ENTRYPOINT можна змінити --entrypoint.


38

Коротко:

  • CMD встановлює командні та / або параметри за замовчуванням, які можна перезаписати з командного рядка, коли контейнер докер працює.
  • Команда та параметри 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"]

Build : 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

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 ["executable", "param1", "param2"…]. Таким чином, якщо зображення призначене для такої послуги, як Apache та Rails, ви б запустили щось подібне CMD ["apache2","-DFOREGROUND"]. Дійсно, ця форма інструкції рекомендується для будь-яких зображень на основі сервісу.

ТОЧКА ВХОДУ:

Найкраще використовувати ENTRYPOINT - це встановити головну команду зображення, дозволяючи запускати це зображення так, як ніби це було саме цією командою (а потім використовувати CMD як прапори за замовчуванням).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.