Dockerfile: инструкции, ENTRYPOINT и CMD, ARG и ENV

↑ Этап 2 · Контейнеры: Docker, docker-compose, Makefile

Обязательно~5 мин чтенияУровень: junior

Зачем это на собесе

Dockerfile — практика каждого собеседования: ENTRYPOINT против CMD, ARG против ENV, exec-форма.

Основные инструкции

ИнструкцияНазначение
FROMбазовый образ (начало стадии)
WORKDIRрабочий каталог (создаётся)
COPYкопирование файлов из контекста или другой стадии (--from, --chown)
ADDкак COPY + распаковка tar и URL (предпочитайте COPY)
RUNвыполнение команды при сборке (создаёт слой)
ENVпеременные окружения (сборка и рантайм)
ARGпеременные только на время сборки
EXPOSEдокументирует порт (не публикует)
USERпользователь для последующих инструкций и запуска
ENTRYPOINTисполняемая команда контейнера
CMDаргументы по умолчанию / команда по умолчанию
HEALTHCHECKпроверка здоровья
VOLUMEточка монтирования тома
LABELметаданные (OCI-аннотации)
STOPSIGNAL, SHELL, ONBUILDсигнал остановки, оболочка, триггеры

ENTRYPOINT и CMD

  • ENTRYPOINT — что запускается (фиксированная часть); docker run image args добавляет args к ENTRYPOINT;
  • CMD — значения по умолчанию, которые заменяются аргументами docker run.
ENTRYPOINT ["dotnet", "Api.dll"]
CMD ["--urls", "http://+:8080"]
# docker run image                 → dotnet Api.dll --urls http://+:8080
# docker run image --urls http://+:9000 → dotnet Api.dll --urls http://+:9000

Без ENTRYPOINT: CMD ["nginx", "-g", "daemon off;"] — команда целиком заменяется (docker run image sh).

Exec-форма против shell-формы

CMD ["nginx", "-g", "daemon off;"]     # exec-форма (JSON-массив): процесс = PID 1, получает сигналы
CMD nginx -g "daemon off;"             # shell-форма: /bin/sh -c "..." — PID 1 это shell, сигналы (SIGTERM) не доходят → остановка через 10 с и SIGKILL

Используйте exec-форму для ENTRYPOINT/CMD. Если нужна подстановка переменных — скрипт-обёртка с exec "$@":

#!/bin/sh
set -e
# подготовка (миграции, генерация конфига из env)
exec "$@"            # exec заменяет shell процессом приложения (PID 1, получает сигналы)
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["dotnet", "Api.dll"]

ARG и ENV

ARGENV
Доступнотолько при сборкепри сборке и в контейнере
Задаётся--build-arg-e, --env-file, Dockerfile
Видно в образев docker history (не для секретов!)в конфигурации образа и контейнере
ARG DOTNET_VERSION=9.0
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} AS build
ARG BUILD_CONFIGURATION=Release
ARG GIT_SHA
ENV ASPNETCORE_URLS=http://+:8080 \
    DOTNET_EULA=1
LABEL org.opencontainers.image.revision=$GIT_SHA

ARG перед FROM действует только для выбора базового образа; внутри стадии ARG нужно объявить заново. Секреты не передавайте через ARG/ENV — используйте RUN --mount=type=secret.

Пример Dockerfile для приложения

# syntax=docker/dockerfile:1.7
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine AS runtime
WORKDIR /app
RUN addgroup -S app && adduser -S app -G app
COPY --chown=app:app ./publish .
USER app
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
  CMD wget -qO- http://localhost:8080/health/live || exit 1
ENTRYPOINT ["dotnet", "Api.dll"]

.dockerignore

Исключает файлы из контекста сборки: .git, bin/, obj/, node_modules/, *.md, .env, Dockerfile: ускоряет сборку, улучшает кэш, не утекают секреты.

COPY против ADD

ADD автоматически распаковывает архивы и качает URL: неявное поведение; используйте COPY. Для загрузки — RUN curl ... | tar с проверкой контрольных сумм.

Лучшие практики

  • фиксированные версии базовых образов (aspnet:9.0.5, по возможности digest);
  • multi-stage для уменьшения размера;
  • объединять команды RUN с очисткой;
  • не root (USER);
  • один процесс на контейнер, stdout/stderr для логов;
  • порядок инструкций под кэш;
  • HEALTHCHECK;
  • метаданные OCI LABEL;
  • линт: hadolint, сканирование: Trivy.

Вопросы с ответами