Главная/Материалы/Материал

Поток кэша сборки

Что переиспользуется, что пересчитывается и почему кэш перестаёт работать.

Решение по каждой инструкции

text
       очередная инструкция
              │
              ▼
   ┌──────────────────────────┐
   │ Изменилась ли сама       │──── да ──┐
   │ инструкция?              │          │
   └──────────┬───────────────┘          │
              │ нет                      │
              ▼                          │
   ┌──────────────────────────┐          │
   │ Для COPY/ADD: изменилось │──── да ──┤
   │ содержимое файлов?       │          │
   └──────────┬───────────────┘          │
              │ нет                      │
              ▼                          ▼
   ┌──────────────────────────┐   ┌─────────────┐
   │ Предыдущий слой взят     │   │  ВЫПОЛНИТЬ  │
   │ из кэша?                 │no─►│  и все      │
   └──────────┬───────────────┘   │  следующие  │
              │ да                └─────────────┘
              ▼
        ┌──────────┐
        │  CACHED  │
        └──────────┘

Как читать

Третья проверка — та, из-за которой кэш «ломается целиком». Слой описывает состояние файловой системы после всех предыдущих; если предыдущее состояние другое, переиспользовать результат нельзя, даже если инструкция та же.

Порядок, при котором кэш работает

text
                                     изменение кода
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"]

Порядок, при котором не работает

text
FROM python:3.13-slim
COPY . .                             ────┐ ← любое изменение
RUN pip install -r requirements.txt      │   любого файла
ENTRYPOINT ["python", "-m", "app"]   ────┘   сбрасывает всё

Разница — в двух строках и в трёх минутах на каждую сборку.

Два разных механизма

text
┌─────────────────────────────────────────────────────────┐
│  Кэш СЛОЁВ                                              │
│  переиспользование результата инструкции                │
│  экспортируется через --cache-to                        │
│  ПЕРЕНОСИТСЯ между машинами и запусками CI              │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  Cache mount (RUN --mount=type=cache)                   │
│  каталог, живущий вне слоёв на машине сборки            │
│  --cache-to его НЕ экспортирует                         │
│  НЕ ПЕРЕНОСИТСЯ в CI                                    │
└─────────────────────────────────────────────────────────┘

Их путают чаще всего. Cache mount ускоряет повторные сборки на той же машине; в конвейере, где каждый запуск на чистом агенте, он не даёт ничего.

Перенос кэша между запусками CI

text
   запуск 1                     registry                запуск 2
   ────────                     ────────                ────────
   сборка  ──── cache-to ────►  имя:buildcache
                                     │
                                     └──── cache-from ────► сборка
                                                            быстрее
bash
docker buildx build \
  --cache-from type=registry,ref=имя:buildcache \
  --cache-to   type=registry,ref=имя:buildcache,mode=max \
  --tag имя:тег --load .

mode=max обязателен.

text
mode=min (умолчание)          mode=max
────────────────────          ────────
экспортируется только         экспортируются все стадии,
последняя стадия              включая установку зависимостей
        │                              │
        ▼                              ▼
слой с зависимостями          кэш работает
в кэш НЕ попадает

Это самая частая причина «кэш настроен, а сборка медленная».

Как проверить, что кэш работает

По времени, а не по числу строк CACHED:

bash
docker build -t проба .
touch src/app/main.py
time docker build -t проба .
РезультатВывод
СекундыКэш работает
МинутыЗависимости пересобираются — проверить порядок

Найти точку сброса:

bash
docker build -t проба . 2>&1 | grep -nE 'CACHED|^#[0-9]+ \[' | head -30

Первая инструкция без CACHED — та, что сбросила кэш.

Вторая причина того же симптома

text
контекст сборки
├── .git/            ← 400 МБ, меняется при каждом коммите
├── __pycache__/     ← меняется при каждом запуске
├── .venv/           ← 200 МБ
└── app/

Без .dockerignore COPY . . видит изменения там, где вы ничего не трогали. Минимальный набор:

text
.git
.venv
__pycache__
*.pyc
.pytest_cache
htmlcov
.coverage

Подробнее

Урок 5.5. Кэш сборки
Урок 5.1. Контекст и .dockerignore
Урок 16.3. Кэш в CI


Навигация

Раздел 05. Dockerfile
Диаграмма слоёв
Главное оглавление

Markdown на GitHub ↗