Главная/Dockerfile/Обзор

Раздел 5. Dockerfile

Dockerfile — это не скрипт установки. Это описание того, как из базового образа получить новый набор слоёв, и одновременно описание того, как запускать полученный образ. Разница принципиальна: скрипт выполняется целиком каждый раз, а Dockerfile выполняется через кэш, и порядок инструкций напрямую определяет, будет ли сборка занимать три секунды или три минуты.

Раздел разбирает все инструкции по единому шаблону: назначение, синтаксис, пример, типичная ошибка и случаи, когда инструкцию применять не следует. Затем переходит к механике: как устроен build cache, что именно его инвалидирует, что даёт BuildKit (cache mounts, secret mounts, параллельная сборка стадий) и как multi-stage builds позволяют собрать приложение в одном окружении, а поставить — в другом.

Материал раздела нейтрален к языку. Применение к Python — в разделе 06.

Цели обучения

После раздела учащийся сможет:

  • объяснить, что такое build context, и сократить его через .dockerignore;
  • применять все базовые инструкции Dockerfile по назначению и объяснять, почему выбрана именно эта;
  • различать exec form и shell form и предсказывать поведение каждой;
  • объяснить разницу между CMD и ENTRYPOINT и корректно комбинировать их;
  • объяснить разницу между ARG и ENV, включая область видимости и попадание в образ;
  • диагностировать инвалидацию build cache и упорядочить инструкции так, чтобы кэш работал;
  • применять возможности BuildKit: cache mounts, secret mounts, bind mounts, heredocs;
  • писать multi-stage builds и собирать конкретную стадию через --target;
  • настраивать HEALTHCHECK и объяснять, когда он не нужен;
  • обеспечивать воспроизводимость сборки: pinned versions, digests, lock files.

Предварительные знания

Материалы

  1. Build context и .dockerignore
    Что именно отправляется daemon при сборке и почему это может занимать минуты. Синтаксис .dockerignore, типичный набор исключений для Python-проекта, влияние контекста на build cache и на утечку файлов в образ.

  2. Базовые инструкции
    FROM, ARG, ENV, WORKDIR, LABEL, USER, EXPOSE, VOLUME, SHELL, STOPSIGNAL, ONBUILD. Для каждой: назначение, синтаксис, пример, типичная ошибка и когда применять не следует. Область видимости ARG и его отличие от ENV.

  3. COPY, ADD и RUN
    Почему COPY предпочтительнее ADD и в каких двух случаях ADD уместен. COPY --from, --chown, --link, --parents. Объединение команд в одном RUN, --no-install-recommends, очистка в том же слое, heredoc-синтаксис.

  4. CMD и ENTRYPOINT
    Exec form против shell form и последствия для сигналов. Все комбинации CMD и ENTRYPOINT с таблицей результирующей команды. Паттерн entrypoint-скрипта и exec "$@". Переопределение при запуске.

  5. Build cache
    Правила инвалидации кэша для каждой инструкции. Почему изменение кода не должно пересобирать зависимости. Порядок инструкций как инженерное решение. Диагностика: чтение вывода сборки, --progress=plain, --no-cache.

  6. BuildKit
    Что изменилось по сравнению с legacy builder. Директива # syntax=docker/dockerfile:1. Cache mounts для менеджеров пакетов, secret mounts вместо build args для паролей, bind mounts вместо копирования, параллельная сборка стадий. docker buildx build и build drivers.

  7. Multi-stage builds
    Разделение окружения сборки и окружения выполнения. Именование стадий, COPY --from, --target, общие базовые стадии. Практическое сравнение размеров. Когда multi-stage не нужен.

  8. HEALTHCHECK
    Синтаксис и параметры --interval, --timeout, --start-period, --start-interval, --retries. Как Docker использует статус health. Отличие от readiness. Почему healthcheck в образе не всегда правильное решение и когда лучше описать его в Compose.

  9. Воспроизводимые сборки
    Pinning base image по tag и по digest, фиксация версий пакетов, lock files, влияние времени сборки на результат. Provenance и SBOM: что это и как получить. Ограничения полной воспроизводимости.

  10. Практические задания
    Лабораторные задания раздела с проверкой результата.

Рекомендуемый порядок чтения

Последовательный: 01 → 02 → 03 → 04 → 05 → 06 → 07 → 08 → 09 → exercises.

Уроки 04 и 05 — ключевые: они объясняют две самые частые категории ошибок в реальных Dockerfile. Урок 09 можно отложить до раздела 11. Production, если сейчас важнее скорость.

Практические задания

ЗаданиеТип
1Измерить размер build context до и после добавления .dockerignoreобяз.
2Собрать образ, намеренно сломать кэш, найти инструкцию-виновника по выводу сборкиобяз.
3Переупорядочить инструкции так, чтобы изменение кода не пересобирало зависимости; измерить время до и послеобяз.
4Построить таблицу результирующих команд для всех комбинаций CMD и ENTRYPOINT и проверить её экспериментальнообяз.
5Преобразовать одностадийную сборку в multi-stage и сравнить размерыобяз.
6Использовать cache mount для менеджера пакетов и измерить эффект на повторной сборкедоп.
7Передать токен через secret mount и доказать через docker history, что он не попал в образдоп.
8Добавить HEALTHCHECK и увидеть переход состояния из starting в healthyдоп.
9Дан Dockerfile, где каждая сборка занимает 4 минуты. Найти три причины и исправитьдиаг.
10Собрать образ, воспроизводимый по digest на двух разных машинах

Полные формулировки — в exercises.md.

Критерии завершения раздела

Раздел пройден, когда учащийся может без подсказок:

  1. Объяснить, что попадёт в образ при COPY . . и как это ограничить.
  2. Предсказать результирующую команду для любой комбинации ENTRYPOINT и CMD.
  3. Назвать, что инвалидирует кэш для COPY, RUN и ARG.
  4. Написать multi-stage Dockerfile, где финальный образ не содержит компилятора и dev-зависимостей.
  5. Объяснить, почему передача пароля через --build-arg небезопасна, и показать альтернативу.
  6. Объяснить, почему ENV с секретом хуже, чем secret mount, даже если значение потом перезаписано.

Проверьте себя: Quiz 05.

Что дальше

Раздел дал универсальные правила сборки. Следующий раздел — центральный в курсе — применяет их к Python и добавляет специфику языка: wheels, зависимости, буферизация вывода, worker-процессы.

Навигация

Диаграмма: поток кэша сборки

← Предыдущий раздел: Containers и lifecycle
Вернуться к главному оглавлению
Следующий раздел: Python внутри Container →

Markdown на GitHub ↗