Почему в Dockerfile сначала указывают версию Python, а потом копируют файлы и устанавливают зависимости
Что проверяют
Понимаете ли вы, что Dockerfile это не скрипт, а описание слоёв, и что порядок инструкций определяет, что попадёт в кэш сборки. Вопрос на стыке разработки и эксплуатации, бэкендерам его задают постоянно.
Как отвечать
Каждая инструкция создаёт слой. Слой берётся из кэша, пока не изменились ни сама инструкция, ни файлы, которые она копирует. Как только слой пересобрался, все следующие пересобираются тоже. Отсюда правило: сверху то, что меняется редко, снизу то, что меняется каждый коммит.
Инструкция FROM идёт первой ещё и по синтаксису, до неё допустим только ARG. Закреплённый тег базового образа задаёт версию интерпретатора и делает сборку воспроизводимой.
Порядок выглядит так:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .Манифест зависимостей копируется отдельно и раньше остального кода. Пока он не изменился, установка берётся из кэша, и правка любого файла проекта пересобирает только последний слой. Если же скопировать сразу весь проект, а зависимости ставить после, кэш будет сбрасываться при каждой правке, и сборка займёт минуты вместо секунд.
Стоит упомянуть файл исключений контекста: без него внутрь попадают история репозитория и локальное виртуальное окружение, и кэш ломается из-за файлов, которые к сборке отношения не имеют.
Где спотыкаются
Копируют весь проект перед установкой зависимостей. Логически всё верно, образ соберётся, но кэш не сработает ни разу, и это самая частая ошибка в питоновских образах.
Второе: не закрепляют версии. Тег базового образа без номера и зависимости без указания версий означают, что образ, собранный сегодня и через месяц, содержит разный код, а воспроизвести старое поведение нечем.
Третье: убирают за собой отдельной инструкцией. Удаление кэша пакетов или сборочных утилит новым RUN образ не уменьшает: предыдущий слой уже записан. Чистить надо в той же инструкции либо собирать образ многоэтапно.