Чем отличается CMD от ENTRYPOINT в DockerFile


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

🔹 CMD

Назначение:

Инструкция CMD задаёт команду по умолчанию, которая будет выполнена при запуске контейнера, если не указана другая команда в момент запуска через docker run.

Синтаксис:

Строковая форма:

<br/>CMD "echo Hello"

— интерпретируется shell'ом (/bin/sh -c).

Exec-форма (рекомендуется):

<br/>CMD \["echo", "Hello"\]

CMD с аргументами:

<br/>CMD \["nginx", "-g", "daemon off;"\]

Особенности:

Может быть переопределена при запуске контейнера:

docker run myimage ls -la

  • — в этом случае ls -la заменит CMD.

  • Может использоваться совместно с ENTRYPOINT для передачи аргументов по умолчанию (см. ниже).

🔹 ENTRYPOINT

Назначение:

Инструкция ENTRYPOINT задаёт основную неизменяемую команду, которую контейнер будет всегда запускать. Даже если пользователь укажет другие команды при запуске контейнера, они будут переданы как аргументы к ENTRYPOINT, а не заменят его.

Синтаксис:

Exec-форма (рекомендуется):

<br/>ENTRYPOINT \["python", "app.py"\]

Shell-форма (использует /bin/sh -c, не рекомендуется):

<br/>ENTRYPOINT "python app.py"

Особенности:

Команда, заданная ENTRYPOINT, не переопределяется обычными параметрами docker run, а дополняется:

<br/>docker run myimage arg1 arg2

— будет интерпретировано как:

<br/>python app.py arg1 arg2

Чтобы переопределить ENTRYPOINT, нужно использовать --entrypoint:

<br/>docker run --entrypoint ls myimage

🔸 Совместное использование ENTRYPOINT и CMD

Можно комбинировать ENTRYPOINT и CMD для задания неизменяемой команды и настраиваемых аргументов по умолчанию:

ENTRYPOINT \["python", "app.py"\]
CMD \["--port=8080"\]

В этом случае:

docker run myimage

\=> выполнит:

python app.py --port=8080

А если при запуске передать аргументы:

docker run myimage --debug

\=> выполнит:

python app.py --debug

— то есть CMD будет заменён.

🔍 Таблица сравнения

Характеристика CMD ENTRYPOINT
Назначение Указывает команду по умолчанию Указывает основную команду
--- --- ---
Переопределяется при docker run Да Нет (аргументы передаются)
--- --- ---
Рекомендуемый синтаксис Exec-форма (["cmd", "arg"]) Exec-форма (["cmd", "arg"])
--- --- ---
Совместимость Может использоваться с ENTRYPOINT Может использовать CMD как аргументы
--- --- ---
Поведение при запуске Заменяется аргументами командной строки Сохраняется, аргументы добавляются
--- --- ---
Shell-поддержка Есть (shell-форма) Есть, но не рекомендуется
--- --- ---

🔧 Примеры

Пример 1: Только CMD

FROM ubuntu
CMD \["echo", "Hello from CMD"\]

docker run myimage # → echo Hello from CMD

docker run myimage ls -la # → ls -la (CMD заменяется)

Пример 2: Только ENTRYPOINT

FROM ubuntu
ENTRYPOINT \["echo", "Hello from ENTRYPOINT"\]

docker run myimage test # → echo Hello from ENTRYPOINT test

docker run myimage ls -la # → echo Hello from ENTRYPOINT ls -la

Пример 3: ENTRYPOINT + CMD

FROM ubuntu
ENTRYPOINT \["echo"\]
CMD \["Hello from CMD"\]

docker run myimage # → echo Hello from CMD

docker run myimage world # → echo world

⚠️ Частые ошибки

  1. Shell-форма ENTRYPOINT: приводит к проблемам с сигналами и PID 1 — лучше использовать exec-форму.

  2. CMD без ENTRYPOINT: легко забыть, что она переопределяется при docker run.

  3. CMD и ENTRYPOINT в shell-форме одновременно: может вызвать нестабильное поведение.

🧠 Когда использовать ENTRYPOINT, а когда CMD

  • Используйте CMD, если хотите предоставить настраиваемую команду по умолчанию, которую пользователь может легко заменить.

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

  • Используйте оба вместе, чтобы сделать ENTRYPOINT основным действием, а CMD — конфигурируемыми аргументами по умолчанию.