Ответ
Инструкция CMD в Dockerfile определяет команду по умолчанию и её аргументы, которые выполняются при запуске контейнера из этого образа. Она имеет две основные формы:
-
Exec-формат (рекомендуется): Параметры передаются как массив JSON-строк.
CMD ["executable", "param1", "param2"]Эта форма позволяет контейнеру корректно получать сигналы завершения (например, SIGTERM), так как процесс запускается напрямую, без оболочки.
-
Shell-формат: Команда выполняется в оболочке (
/bin/sh -c).CMD command param1 param2
Ключевые моменты:
- В Dockerfile может быть только одна действующая инструкция
CMD. Если их несколько, выполнится только последняя. - Аргументы
CMDможно переопределить при запуске контейнера, указав новую команду в концеdocker run <image> <new_command>. - Часто
CMDиспользуется в паре сENTRYPOINT. В этом случаеENTRYPOINTопределяет фиксированную исполняемую команду, аCMDзадаёт изменяемые по умолчанию аргументы для неё.
Пример комбинации ENTRYPOINT + CMD:
# Фиксированная команда
ENTRYPOINT ["nginx"]
# Аргументы по умолчанию
CMD ["-g", "daemon off;"]
При таком подходе запуск docker run my-nginx выполнит nginx -g "daemon off;", но можно легко изменить аргументы: docker run my-nginx -g "daemon on;" -c /custom.conf.
Ответ 18+ 🔞
А, так вот ты о чём, про эту самую CMD в докере! Ну, слушай, сейчас разжуём, как говорится, до состояния детского питания.
Представь, что ты собрал себе образ — этакий красивый, упакованный чемодан с софтом. Так вот, CMD — это записка внутри, которая говорит: «Эй, когда откроешь этот чемодан (запустишь контейнер), сделай вот это по умолчанию». Без неё контейнер просто откроется и будет тупить, как мартышлюшка перед бананом, не зная, что делать.
Теперь, ёпта, есть два главных способа эту записку написать, и тут важно не проебаться.
Первый способ, правильный и крутой (Exec-формат). Тут всё чётко, по-взрослому. Команду и её аргументы ты пишешь как массив строк, в JSON-стиле.
CMD ["nginx", "-g", "daemon off;"]
Почему он топовый? Потому что процесс запускается напрямую, без лишней оболочки посередине. Это значит, что если ты скажешь контейнеру «закройся», он это корректно услышит (сигналы типа SIGTERM дойдут). Без этого он может тупо проигнорировать твой docker stop и висеть, пока его не прибьют дубиной.
Второй способ, попроще (Shell-формат). Тут ты пишешь команду почти как в терминале.
CMD nginx -g "daemon off;"
Выглядит вроде проще, да? Но под капотом-то докер оборачивает это в /bin/sh -c 'твоя команда'. А оболочка — она хитрая жопа, может сигналы перехватывать, переменные подменять. Иногда это нужно, но чаще — просто лишняя головная боль и доверия ебать ноль к тому, как она себя поведёт.
Важные фишки, которые надо запомнить, чтобы не охуеть потом:
- В одном Dockerfile только одна
CMDработает. Если ты их напишешь несколько, сработает самая последняя, а все предыдущие — накрылись медным тазом. Докер просто возьмёт последнюю и похуй на остальные. - Эту дефолтную команду можно перебить нахуй прямо при запуске. Запускаешь контейнер и в конце пишешь свою команду:
docker run my-image /bin/bash. И всё, оригинальнаяCMDлетит в пизду, выполняется то, что ты сказал.
А теперь, блядь, самый сочный кусок — дуэт ENTRYPOINT и CMD. Это как брак, где один — начальник, а второй — подчинённый.
ENTRYPOINT— это железобетонная, фиксированная команда. Её уже так просто не переопределишь.CMD— это аргументы по умолчанию для этой команды. Их-то как раз легко поменять.
Смотри, как это гениально работает:
# Это наш начальник, железный каркас. Будет всегда "nginx".
ENTRYPOINT ["nginx"]
# А это аргументы по умолчанию, которые мы можем менять.
CMD ["-g", "daemon off;"]
Когда ты просто делаешь docker run my-nginx, выполняется nginx -g "daemon off;".
Но если тебе эти аргументы не подходят — да похуй! Ты можешь свои передать, и они заменят CMD:
docker run my-nginx -g "daemon on;" -c /my-cool-config.conf
И выполнится уже nginx -g "daemon on;" -c /my-cool-config.conf. Видишь? Команда (nginx) осталась неизменной, а аргументы — твои. Красота, ёбать копать!
Короче, суть в чём: CMD — это твоя «запасная» инструкция для ленивых запусков, которую всегда можно и нужно переписать, если мозги работают. А с ENTRYPOINT она создаёт просто овердохуища гибкую связку. Главное — форму exec-форму использовать, чтобы потом не было волнения ебать, почему контейнер не останавливается.