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

Ответ

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

  • ENTRYPOINT задает исполняемую команду, которая всегда будет запущена. Её сложно переопределить. Аргументы, переданные в docker run, добавляются в конец команды ENTRYPOINT.
  • CMD задает аргументы по умолчанию для ENTRYPOINT. Если ENTRYPOINT не указан, CMD определяет команду для выполнения. Аргументы CMD легко переопределяются аргументами из docker run.

Практические сценарии:

  1. ENTRYPOINT как исполняемый файл, CMD как аргументы по умолчанию (наиболее полезный вариант):

    ENTRYPOINT ["curl"]
    CMD ["--help"]
    • docker run my-curl выполнит curl --help.
    • docker run my-curl -s https://example.com выполнит curl -s https://example.com (аргументы CMD переопределены).
  2. Только CMD (для одноразовых команд):

    CMD ["nginx", "-g", "daemon off;"]
    • docker run my-nginx запустит nginx.
    • docker run my-nginx sh полностью переопределит CMD и запустит оболочку.
  3. Только ENTRYPOINT (для создания контейнера как бинарника):

    ENTRYPOINT ["python", "app.py"]
    • docker run my-app выполнит python app.py.
    • docker run my-app --debug выполнит python app.py --debug.

Рекомендация: Используйте ENTRYPOINT для фиксированной части команды (например, интерпретатор или основной бинарник), а CMD для предоставления изменяемых по умолчанию аргументов. Это делает контейнер похожим на исполняемую программу.

Ответ 18+ 🔞

Давай разберём эту тему про ENTRYPOINT и CMD, а то у многих тут волнение ебать начинается, когда они в Dockerfile смотрят. Представь, что контейнер — это какой-нибудь полупидор, который должен что-то делать, когда ты его запускаешь. Так вот, эти две директивы и говорят ему, что именно.

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

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

А теперь на живых примерах, чтобы совсем ядрёна вошь не съела:

  1. Классика жанра: ENTRYPOINT — программа, CMD — её довесок.

    ENTRYPOINT ["curl"]
    CMD ["--help"]
    • Запустил docker run my-curl — получил curl --help. Всё просто, как три копейки.
    • А вот если запустил docker run my-curl -s https://example.com — то выполнится уже curl -s https://example.com. Видишь? Аргументы из CMD накрылись медным тазом, потому что ты приказал своё. Но сам curl — нет, он железно стоит на своём месте благодаря ENTRYPOINT.
  2. Только CMD — для простых смертных.

    CMD ["nginx", "-g", "daemon off;"]
    • docker run my-nginx — и nginx пошёл работать.
    • Но если ты такой хитрожопый и скажешь docker run my-nginx sh — то всё, приехали. CMD выкинули нахуй, и контейнер запустит тебе оболочку. Полный переворот.
  3. Только ENTRYPOINT — когда ты уверен в себе как хуй с горы.

    ENTRYPOINT ["python", "app.py"]
    • docker run my-app — выполнит python app.py. Без вариантов.
    • docker run my-app --debug — выполнит python app.py --debug. Твои аргументы просто прицепили в хвост.

Так какого хуя со всем этим делать? Самый адекватный совет — используй ENTRYPOINT для чего-то главного и нерушимого (типа интерпретатора python или бинарника curl), а CMD — для аргументов по дефолту, которые ты, скорее всего, захочешь поменять. Тогда твой контейнер будет вести себя как нормальная программа: у неё есть имя (ENTRYPOINT), а флаги (CMD) ты можешь подкручивать под себя. И никакого пиздеца.