Чем отличаются CMD и ENTRYPOINT
Обе инструкции задают, что запускается в контейнере. Разница — в том, как их переопределяют:
CMD— команда по умолчанию. Всё, что написано после имени образа вdocker run, полностью её заменяет.ENTRYPOINT— основная программа образа. Аргументы изdocker runне заменяют её, а добавляются к ней. Заменить её можно только ключом--entrypoint.
Пример с CMD
FROM alpine
CMD ["echo", "Привет, мир"]Соберите образ в папке с этим Dockerfile (docker build -t hello-cmd .) и запустите:
$ docker run --rm hello-cmd
Привет, мирА docker run --rm hello-cmd date вместо echo запустит date и выведет текущие дату и время: CMD заменился целиком.
Пример с ENTRYPOINT и CMD вместе
FROM alpine
ENTRYPOINT ["echo", "Привет,"]
CMD ["мир"]Сборка — docker build -t hello-ep ., запуск:
$ docker run --rm hello-ep
Привет, мир
$ docker run --rm hello-ep Docker
Привет, DockerENTRYPOINT осталась, а CMD (здесь — аргумент по умолчанию мир) заменился на Docker. Так делают образы- программы: docker run образ --help передаёт --help самой программе.
Заменить и ENTRYPOINT:
docker run --rm --entrypoint sh hello-ep -c 'echo другая команда'Таблица
| Без ENTRYPOINT | ENTRYPOINT ["prog"] | |
|---|---|---|
| Без CMD | ошибка: запускать нечего | prog |
CMD ["arg"] | arg (как программа) | prog arg |
docker run образ x y | x y | prog x y |
Exec-форма и shell-форма
У обеих инструкций две формы записи:
- exec-форма — список в квадратных скобках и двойных кавычках:
CMD ["python", "app.py"]. Программа запускается напрямую; - shell-форма — строкой:
CMD python app.py. Команда запускается через/bin/sh -c.
Используйте exec-форму. В shell-форме главным процессом контейнера становится оболочка sh, и сигнал остановки от docker stop до программы может не дойти: Docker подождёт 10 секунд и завершит контейнер принудительно, а программа не успеет сохранить данные. Кроме того, ENTRYPOINT в shell-форме игнорирует и CMD, и аргументы docker run.
В exec-форме кавычки — только двойные. С одинарными (CMD ['python', 'app.py']) Docker не распознает список и запустит строку через оболочку как shell-форму — с непонятной ошибкой.
Что выбрать
- Обычный сервис или приложение — достаточно
CMD. Его легко заменить при отладке:docker run -it --rm образ sh. - Образ — обёртка над одной утилитой —
ENTRYPOINTс программой иCMDс аргументами по умолчанию. - Нужно что-то подготовить перед запуском (проверить настройки, дождаться базы) —
ENTRYPOINTсо скриптом, который в конце выполняетexec "$@": так программа изCMDзаменяет собой скрипт и получает сигналы. Так устроены многие официальные образы, например nginx и postgres.
Если в Dockerfile несколько CMD или несколько ENTRYPOINT, действует только последняя инструкция каждого вида. И ещё одна тонкость: если в своём Dockerfile задать ENTRYPOINT, то CMD, унаследованный от базового образа, сбрасывается — нужный CMD пишут заново в своём файле.