Ответ
Инструкция CMD в Dockerfile задаёт команду и её аргументы по умолчанию, которые будут выполнены при запуске контейнера, если пользователь не укажет свою команду в docker run. В одном Dockerfile может быть только одна эффективная инструкция CMD (используется последняя).
Форматы записи:
-
Exec-форма (рекомендуется):
CMD ["executable", "param1", "param2"]- Команда выполняется напрямую, без оболочки (
/bin/sh). - Переменные окружения не интерполируются, но это более чистый сигнальный механизм (PID 1).
CMD ["nginx", "-g", "daemon off;"]
- Команда выполняется напрямую, без оболочки (
-
Shell-форма:
CMD command param1 param2- Выполняется через
/bin/sh -c. - Поддерживает подстановку переменных окружения, но хуже обрабатывает сигналы остановки.
CMD nginx -g 'daemon off;'
- Выполняется через
Взаимодействие с ENTRYPOINT:
- Если определён
ENTRYPOINT, тоCMDзадаёт аргументы по умолчанию для него. - Аргументы
CMDможно полностью переопределить при запуске контейнера.
Практический пример из моего опыта:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# ENTRYPOINT задаёт интерпретатор, CMD — скрипт по умолчанию
ENTRYPOINT ["python"]
CMD ["app.py"]
Запуск контейнера:
docker run my-app # Выполнит: python app.py
docker run my-app test_runner.py # Выполнит: python test_runner.py (CMD переопределён) Ответ 18+ 🔞
Смотри, объясню тебе про эту самую CMD в Dockerfile, чтобы ты не охуел от всей этой документации. Это, по сути, команда по умолчанию, которую контейнер будет выполнять, когда ты его запустишь, если сам ничего не придумаешь. В одном файле может быть только одна рабочая CMD — последняя, остальные, понятное дело, накрываются медным тазом.
Как это записывают, блядь:
-
Exec-форма (её все умные дяди советуют):
CMD ["исполняемый_файл", "параметр1", "параметр2"]- Тут всё честно, без посредников. Команда запускается напрямую, без всякого
/bin/sh. - Переменные окружения внутри не раскрываются, но зато сигналы типа
SIGTERMдоходят как надо, что для PID 1 — святое дело.CMD ["nginx", "-g", "daemon off;"]
- Тут всё честно, без посредников. Команда запускается напрямую, без всякого
-
Shell-форма:
CMD команда параметр1 параметр2- А вот это уже через оболочку, типа
/bin/sh -c. - Плюс — переменные окружения работают. Минус — с обработкой сигналов для остановки контейнера начинается пиздец и бардак, потому что PID 1 теперь у этой самой оболочки.
CMD nginx -g 'daemon off;'
- А вот это уже через оболочку, типа
А если ещё и ENTRYPOINT есть?
Вот тут начинается магия, ёпта. Если ты определил ENTRYPOINT, то CMD становится не полноценной командой, а просто набором аргументов по умолчанию для этого самого ENTRYPOINT. И самое главное — эти аргументы из CMD ты можешь запросто перебить, когда будешь контейнер запускать. Удобно, как блядь.
Пример из жизни, чтобы совсем всё стало ясно: Допустим, делаем мы простенький питонячий сервис.
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# ENTRYPOINT — это как будто фиксированный инструмент (python)
ENTRYPOINT ["python"]
# А CMD — это дефолтный скрипт, который мы этим инструментом запустим
CMD ["app.py"]
Теперь смотри, как это работает на практике:
# Просто запускаем — выполнится то, что по умолчанию: python app.py
docker run my-app
# А тут мы говорим: "Нахуй твой app.py, запускай test_runner.py"
# И выполнится: python test_runner.py. CMD переопределён, ENTRYPOINT остался.
docker run my-app test_runner.py
Вот и вся философия. ENTRYPOINT — это как будто молоток, а CMD — гвоздь, который ты по умолчанию собираешься забивать. Но если захочешь, можешь взять и шуруп вместо гвоздя, молоток-то останется тем же.