Dockerfile

Материал из llmdocs — справочник разработчика
Dockerfile
Типформат описания сборки образа
РазработчикDocker, Inc.
Появился2013
Сборщик по умолчаниюBuildKit (с Docker Engine 23.0, 2023)
Многоэтапная сборкас Docker 17.05 (2017)
Альтернативное имяContainerfile (Podman, Buildah)
Линтерhadolint

Dockerfile — текстовый файл с последовательностью инструкций, по которым Docker (или совместимый сборщик) собирает образ контейнера: с какого базового образа начать, какие файлы скопировать, какие команды выполнить и что запускать при старте контейнера. Dockerfile хранится в репозитории рядом с кодом и превращает сборку окружения в воспроизводимый, версионируемый процесс (см. Контейнеризация).

Формат появился вместе с Docker в 2013 году и стал стандартом де-факто: его понимают Podman и Buildah (там он может называться Containerfile), kaniko, облачные сборщики и CI-системы.

Пример

Типичный Dockerfile для веб-приложения на Python:

# syntax=docker/dockerfile:1
FROM python:3.13-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1
WORKDIR /app

# сначала только зависимости — этот слой кэшируется, пока они не меняются
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

# потом код приложения
COPY . .

RUN useradd --create-home app
USER app

EXPOSE 8000
HEALTHCHECK CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
docker build -t myapp:1.0 .      # собрать образ из Dockerfile в текущем каталоге
docker run -p 8000:8000 myapp:1.0

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

Инструкция Назначение
FROM базовый образ; начинает новый этап сборки
RUN выполнить команду при сборке (установка пакетов)
COPY скопировать файлы из контекста сборки в образ
ADD как COPY, но умеет скачивать URL и распаковывать архивы
WORKDIR рабочий каталог для последующих инструкций
ENV переменная окружения в образе и контейнере
ARG параметр, доступный только во время сборки
USER от какого пользователя выполнять команды и запускать процесс
EXPOSE документирует порт, который слушает приложение
CMD команда по умолчанию при запуске контейнера
ENTRYPOINT исполняемый файл, к которому добавляются аргументы CMD
HEALTHCHECK команда проверки работоспособности
LABEL метаданные образа

Полное описание — в справочнике Docker.[1]

CMD и ENTRYPOINT

CMD задаёт команду, которую легко заменить: docker run myapp bash запустит оболочку вместо приложения. ENTRYPOINT фиксирует исполняемый файл, а CMD превращается в его аргументы по умолчанию — так делают образы-утилиты. Обе инструкции лучше писать в exec-форме — JSON-массивом ["uvicorn", "main:app"]. В shell-форме (CMD uvicorn main:app) процесс запускается через /bin/sh -c, оболочка становится PID 1 и не передаёт приложению сигнал SIGTERM, из-за чего контейнер останавливается только по тайм-ауту.

Слои и кэш

Каждая инструкция RUN, COPY и ADD создаёт новый слой образа. Сборщик кэширует слои: если инструкция и её входные данные не изменились, слой берётся из кэша. Как только один слой меняется, все последующие пересобираются.[4] Отсюда главное правило порядка инструкций — от редко меняющихся к часто меняющимся: сначала системные пакеты, затем файл зависимостей и их установка, и только в конце — код приложения. Иначе любая правка кода заново скачивает все библиотеки.

Файл .dockerignore исключает из контекста сборки лишнее — .git, node_modules, .venv, локальные секреты, — ускоряя сборку и не давая этим файлам попасть в образ.

Многоэтапная сборка

Компиляторы и инструменты сборки не нужны в итоговом образе. Многоэтапная сборка позволяет собрать приложение в одном образе, а скопировать результат в другой, минимальный:[3]

FROM golang:1.25 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/server ./cmd/server

FROM gcr.io/distroless/static-debian12
COPY --from=build /out/server /server
USER nonroot
ENTRYPOINT ["/server"]

Итоговый образ содержит только бинарник и занимает единицы мегабайт вместо сотен.

BuildKit

С Docker Engine 23.0 (2023) сборку по умолчанию выполняет BuildKit. Он параллельно собирает независимые этапы, пропускает неиспользуемые и добавляет возможности: кэш-монтирования для менеджеров пакетов (RUN --mount=type=cache), безопасную передачу секретов при сборке (RUN --mount=type=secret), сборку под несколько архитектур (docker buildx build --platform linux/amd64,linux/arm64).[5] Первая строка # syntax=docker/dockerfile:1 подключает актуальную версию синтаксиса.

Хорошие практики

  • Используйте небольшие официальные базовые образы (-slim, alpine, distroless) и фиксируйте их версии, а для полной воспроизводимости — дайджест @sha256:....
  • Объединяйте установку и очистку кэша пакетного менеджера в одной инструкции RUN: удаление файлов в следующем слое не уменьшает размер образа.
  • Не запускайте процесс от root — добавьте USER.
  • Не записывайте секреты в ENV, ARG или файлы образа: они остаются в слоях и видны любому, у кого есть образ.
  • Проверяйте Dockerfile линтером hadolint[6] и сканируйте образ на уязвимости.
  • Готовый образ публикуйте в реестр с осмысленными тегами — версией и хешем коммита, а не только latest.[2]

Формат хранения готового образа описан в статье Образ контейнера и OCI, а запуск нескольких контейнеров вместе — в статье Docker Compose.

См. также

Источники

  1. Docker Docs — Dockerfile reference
  2. Docker Docs — Building best practices
  3. Docker Docs — Multi-stage builds
  4. Docker Docs — Docker build cache
  5. Docker Docs — BuildKit
  6. hadolint — Dockerfile linter