Кеш: чем он отличается от артефактов
Ускоряем установку зависимостей между прогонами. Ключ по хешу lock-файла и разбор, почему кешировать node_modules при npm ci бессмысленно.
Две похожие сущности с разной задачей
Артефакты вы уже знаете: они передают файлы дальше по пайплайну. Кеш решает другую задачу, он переносит файлы между прогонами.
Разница в направлении. Артефакт едет вперёд, от стадии к стадии внутри одного пайплайна. Кеш едет вбок, из вчерашнего пайплайна в сегодняшний.
Отсюда и правило выбора. Результат сборки, который нужен деплою, это артефакт. Скачанные зависимости, которые не жалко потерять, это кеш.
Материалы урока:
git pull --no-rebase upstream main
cp lesson-08-cache/pipeline.yml .gitlab-ci.yml
Ключ решает всё
build:
image: node:22-alpine
cache:
key:
files:
- package-lock.json
paths:
- .npm
script:
- npm ci --cache .npm --prefer-offline
- npm run build
key.files считает хеш от перечисленных файлов, и он попадает в имя кеша.
В логе это видно:
Checking cache for 0_package-lock-69002804654f84e32d6750cf64eeedd8a1476ef2-protected...
.npm: found 21 matching artifact files and directories
Successfully extracted cache
Поменяли зависимости — поменялся package-lock.json — поменялся хеш — кеш
поехал новый. Не поменяли, значит переиспользуется старый. Ровно то
поведение, которое нужно.
Ключом может быть и статичная строка (key: node-deps), но тогда после
обновления зависимостей вы будете тянуть протухший кеш и разбираться,
почему в сборке старая версия пакета.
В key.files помещается максимум два файла. Для монорепозитория с пятью
lock-файлами это ограничение всплывает сразу, и обходят его отдельным кешем
на каждый пакет.
Почему .npm, а не node_modules
Самая частая ошибка в этом месте: кешируют node_modules. С npm install
это работает, с npm ci бессмысленно.
npm ci начинает работу с того, что удаляет node_modules целиком.
Такой у него контракт: воспроизводимая установка с нуля по lock-файлу.
Восстановленная из кеша папка будет снесена в первую же секунду.
Поэтому кешируют папку загрузок npm, а не установленные пакеты:
- npm ci --cache .npm --prefer-offline
--cache .npm переносит весь кеш npm внутрь проекта: и скачанные архивы
пакетов, и метаданные реестра. По умолчанию он лежит в домашней папке, а
GitLab кеширует только пути внутри проекта. --prefer-offline велит
сначала смотреть в этот кеш и лезть в сеть только за тем, чего нет.
Насколько это ускоряет
На учебном проекте с двумя пакетами разница копеечная: установка занимает 392 мс против 507 мс. Кеш здесь не столько ускоряет, сколько показывает механику.
Эффект появляется на реальных зависимостях. Фронтенд с полутысячей пакетов ставится минуту-полторы с нуля и секунд двадцать из кеша, и это на каждом пайплайне, на каждой ветке, у каждого разработчика.
Смотреть надо не на общее время job, а на строки Restoring cache и
Created cache в логе: сколько занял сам обмен с хранилищем. Если кеш
весит сотни мегабайт, скачивание может съесть выигрыш от установки.
Кеш может врать
У кеша нет гарантий. GitLab обещает «постараться», а не «сохранить»: кеш живёт на конкретном раннере или в объектном хранилище, чистится по своим правилам и может просто не найтись.
Пайплайн обязан работать при пустом кеше. Если сборка зелёная только когда кеш подхватился, это уже не ускорение, а скрытая зависимость.
Отсюда практика: cache для того, что скачивается заново, artifacts для
того, что должно доехать гарантированно. И Clear runner caches в
интерфейсе, когда сборка начала вести себя странно без явных причин.
Что важно запомнить
Артефакты передают файлы вперёд по стадиям, кеш переносит их между прогонами пайплайна.
key.files привязывает кеш к хешу lock-файла: обновились зависимости —
приехал новый кеш.
При npm ci кешируют .npm с флагом --cache .npm, потому что
node_modules эта команда удаляет перед установкой.
Кеш не гарантирован: пайплайн должен собираться и с пустым кешем.
Дальше учимся управлять тем, какие job вообще запускаются: rules,
ручные кнопки и ветки.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс