Поток кэша сборки
Что переиспользуется, что пересчитывается и почему кэш перестаёт работать.
Решение по каждой инструкции
очередная инструкция
│
▼
┌──────────────────────────┐
│ Изменилась ли сама │──── да ──┐
│ инструкция? │ │
└──────────┬───────────────┘ │
│ нет │
▼ │
┌──────────────────────────┐ │
│ Для COPY/ADD: изменилось │──── да ──┤
│ содержимое файлов? │ │
└──────────┬───────────────┘ │
│ нет │
▼ ▼
┌──────────────────────────┐ ┌─────────────┐
│ Предыдущий слой взят │ │ ВЫПОЛНИТЬ │
│ из кэша? │no─►│ и все │
└──────────┬───────────────┘ │ следующие │
│ да └─────────────┘
▼
┌──────────┐
│ CACHED │
└──────────┘
Как читать
Третья проверка — та, из-за которой кэш «ломается целиком». Слой описывает состояние файловой системы после всех предыдущих; если предыдущее состояние другое, переиспользовать результат нельзя, даже если инструкция та же.
Порядок, при котором кэш работает
изменение кода
Dockerfile сбрасывает с этой строки
────────────────────────────────────────────────────────────
FROM python:3.13-slim │
ENV PYTHONUNBUFFERED=1 │ редко меняется
RUN apt-get update && apt-get install │
COPY requirements.txt . │
RUN pip install -r requirements.txt │
COPY app/ ./app/ ────┘ ← только отсюда
USER 10001:10001
ENTRYPOINT ["python", "-m", "app"]
Порядок, при котором не работает
FROM python:3.13-slim
COPY . . ────┐ ← любое изменение
RUN pip install -r requirements.txt │ любого файла
ENTRYPOINT ["python", "-m", "app"] ────┘ сбрасывает всё
Разница — в двух строках и в трёх минутах на каждую сборку.
Два разных механизма
┌─────────────────────────────────────────────────────────┐
│ Кэш СЛОЁВ │
│ переиспользование результата инструкции │
│ экспортируется через --cache-to │
│ ПЕРЕНОСИТСЯ между машинами и запусками CI │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Cache mount (RUN --mount=type=cache) │
│ каталог, живущий вне слоёв на машине сборки │
│ --cache-to его НЕ экспортирует │
│ НЕ ПЕРЕНОСИТСЯ в CI │
└─────────────────────────────────────────────────────────┘
Их путают чаще всего. Cache mount ускоряет повторные сборки на той же машине; в конвейере, где каждый запуск на чистом агенте, он не даёт ничего.
Перенос кэша между запусками CI
запуск 1 registry запуск 2
──────── ──────── ────────
сборка ──── cache-to ────► имя:buildcache
│
└──── cache-from ────► сборка
быстрее
docker buildx build \
--cache-from type=registry,ref=имя:buildcache \
--cache-to type=registry,ref=имя:buildcache,mode=max \
--tag имя:тег --load .
mode=max обязателен.
mode=min (умолчание) mode=max
──────────────────── ────────
экспортируется только экспортируются все стадии,
последняя стадия включая установку зависимостей
│ │
▼ ▼
слой с зависимостями кэш работает
в кэш НЕ попадает
Это самая частая причина «кэш настроен, а сборка медленная».
Как проверить, что кэш работает
По времени, а не по числу строк CACHED:
docker build -t проба .
touch src/app/main.py
time docker build -t проба .
| Результат | Вывод |
|---|---|
| Секунды | Кэш работает |
| Минуты | Зависимости пересобираются — проверить порядок |
Найти точку сброса:
docker build -t проба . 2>&1 | grep -nE 'CACHED|^#[0-9]+ \[' | head -30
Первая инструкция без CACHED — та, что сбросила кэш.
Вторая причина того же симптома
контекст сборки
├── .git/ ← 400 МБ, меняется при каждом коммите
├── __pycache__/ ← меняется при каждом запуске
├── .venv/ ← 200 МБ
└── app/
Без .dockerignore COPY . . видит изменения там, где вы ничего не трогали. Минимальный набор:
.git
.venv
__pycache__
*.pyc
.pytest_cache
htmlcov
.coverage
Подробнее
Урок 5.5. Кэш сборки
Урок 5.1. Контекст и .dockerignore
Урок 16.3. Кэш в CI