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

Ответ

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

CMD (Command)

Назначение:

  • Предоставляет команду по умолчанию для исполняемого файла контейнера.
  • Может предоставлять аргументы по умолчанию для ENTRYPOINT.
  • Если в Dockerfile указано несколько CMD, используется только последняя.

Поведение при запуске:

  • Легко переопределяется при запуске контейнера, передав новую команду в docker run <image> <новая_команда>. Это позволяет пользователю запускать произвольные команды внутри контейнера.
  • Если ENTRYPOINT не указан, CMD определяет основную команду, которая будет выполнена.

Пример:

FROM alpine
CMD ["echo", "Hello from CMD"]
  • Запуск: docker run <image> выведет Hello from CMD.
  • Переопределение: docker run <image> echo "Overridden CMD" выведет Overridden CMD.

Почему используется: Для задания команды по умолчанию, которая может быть легко изменена пользователем контейнера, например, для запуска интерактивной оболочки или выполнения скрипта.

ENTRYPOINT (Entrypoint)

Назначение:

  • Определяет основную команду или исполняемый файл, который всегда будет запускаться при старте контейнера.
  • Превращает образ в исполняемый файл, делая его похожим на обычную программу.
  • Аргументы, переданные в docker run, или команда из CMD (если она есть), добавляются как аргументы к ENTRYPOINT.

Поведение при запуске:

  • Не переопределяется напрямую аргументами docker run. Аргументы docker run становятся параметрами для ENTRYPOINT.
  • Для переопределения ENTRYPOINT необходимо явно использовать флаг --entrypoint в docker run.

Пример:

FROM alpine
ENTRYPOINT ["echo"]
CMD ["Hello from ENTRYPOINT"]
  • Запуск: docker run <image> выведет Hello from ENTRYPOINT (CMD используется как аргумент для ENTRYPOINT).
  • Передача аргументов: docker run <image> "New argument" выведет New argument (CMD заменяется на "New argument").
  • Переопределение ENTRYPOINT: docker run --entrypoint "/bin/sh" <image> запустит /bin/sh внутри контейнера.

Почему используется: Для создания контейнера, который ведет себя как исполняемая программа (например, утилита командной строки или сервис), где ENTRYPOINT является этой программой, а CMD — ее аргументами по умолчанию.

Ключевое отличие:

  • CMD предоставляет аргументы по умолчанию для ENTRYPOINT или команду по умолчанию, которую легко переопределить.
  • ENTRYPOINT определяет основной исполняемый файл контейнера, который не меняется, а принимает CMD или аргументы docker run как свои параметры.

Ответ 18+ 🔞

А, ну вот, опять про эту парочку, CMD и ENTRYPOINT, блядь. Слушай, как будто про семейную пару какую-то, где один — упёртый, как валенок, а второй — тряпка, которую можно выкрутить как угодно. Ёпта, сейчас разложу по полочкам, чтобы даже мартышлюшка поняла.

CMD — это как предложение по умолчанию, которое всем похуй.

Представь, ты заходишь в кафе, а там меню. И на нём написано: «По умолчанию мы вам принесём кофе». Это и есть CMD. Но если ты, сука, такой умный и крикнешь: «Нет, мне чай!», то официант (читай — Docker) такой: «Окей, похуй, будет тебе чай». Он легко переписывается.

Вот смотри, пример, чтобы мозг не взорвался:

FROM alpine
CMD ["echo", "Hello from CMD"]
  • Запускаешь просто образ: docker run <image> — и тебе вежливо плюёт в консоль: Hello from CMD.
  • А если ты хитрая жопа и хочешь своё? docker run <image> echo "Overridden CMD" — и всё, привет, Overridden CMD. CMD послан нахуй, делается то, что ты сказал.

Зачем это нужно? Ну, чтобы контейнер из коробки что-то делал, но любой распиздяй мог это перебить своей командой. Типа запустить /bin/sh вместо сервера и поковыряться внутри.


А теперь ENTRYPOINT — это уже не предложение, а приговор, блядь.

Это как если бы ты пришёл в ту же забегаловку, а тебе сразу вручают в руки ложку и сажают за миску с борщом. Ты можешь попросить добавить сметаны или чеснока (это будут аргументы), но саму миску борща тебе не поменять. Хочешь другую еду? Придётся орать на весь зал «Я ХОЧУ ПИЦЦУ!» (это флаг --entrypoint).

Смотри, как это выглядит в деле:

FROM alpine
ENTRYPOINT ["echo"]
CMD ["Hello from ENTRYPOINT"]
  • Запускаешь образ: docker run <image>. ENTRYPOINT — это команда echo, а CMD — её аргумент по умолчанию. На выходе: Hello from ENTRYPOINT.
  • Хочешь другой текст? Кричи его при запуске: docker run <image> "New argument". ENTRYPOINT остаётся echo, а твой крик становится новым аргументом. Вывод: New argument. CMD опять нахуй.
  • А если тебе вдруг борщ надоел и захотелось пиццы? Тогда надо орать специальное заклинание: docker run --entrypoint "/bin/sh" <image>. Вот теперь твой ENTRYPOINT — это шелл, и ты в контейнере.

Зачем это нужно? Чтобы сделать из контейнера такую этакую утилиту, как будто программа. ENTRYPOINT — это сама программа (например, curl или nginx), а всё остальное — её флаги и аргументы, которые можно задать по умолчанию через CMD или передать при запуске.


Короче, суть в чём, чтобы не ебать мозг:

  • CMD — это что запустить по умолчанию. Легко переопределяется, если просто что-то сказать после имени образа. Используется, когда образ — это типа «окружение», в котором можно делать разное.
  • ENTRYPOINT — это чем является контейнер. Он не меняется просто так. Всё, что ты скажешь после имени образа, станет аргументами для этой фиксированной команды. Используется, когда образ — это «исполняемый файл», типа готовой программы.

Сочетаются они так: ENTRYPOINT — это пушка, а CMD — патроны по умолчанию. Но если ты принёс свои патроны (аргументы в docker run), то дефолтные летят в мусорку. Вот и вся магия, блядь. Не благодари.