GH GambleHub

Оптимизация сборки и кеширование

(Раздел: Технологии и Инфраструктура)

Краткое резюме

Скорость CI/CD в iGaming напрямую влияет на частоту релизов, стоимость минут и устойчивость p99 при пиковых нагрузках. Ключ — правильные кэши (зависимости, артефакты, слои контейнеров, промежуточные результаты компиляции), инкрементальные сборки и детерминированность. «Хорошая» сборка быстро повторяется при неизменном вводе, а кэш-инвалидация предсказуема и контролируема.


1) Карта кэшей и что мы кэшируем

Зависимости: пакеты NPM/pnpm, pip wheels/Poetry, Maven/Gradle, Go моды, Cargo crates, NuGet.
Промежуточные артефакты компиляции: `~/.cache/pip`, `~/.m2`, `.gradle`, `~/.cargo/registry/`, `$GOMODCACHE`, `target/`, `build/`, `node_modules/.pnpm-store`.
Контейнерные слои: Docker layer cache (BuildKit/GHA cache), registry-based кэш, multi-stage.
Инструменты и SDK: toolchains/микрообразы (JDK, Node, Python, Rustup targets).
Moно/полирепо-мета: кэш Nx/Turborepo/Bazel remote-cache для задач (lint/test/build).
Тест-данные и e2e фикстуры: снепшоты БД, скомпилированные UI-бандлы.
ML/данные: подготовленные датасеты, эмбеддинги, скомпилированные движки (TensorRT/ONNX).


2) Принципы быстрой и предсказуемой сборки

1. Детерминированность: фиксируйте версии (lockfiles), pin базовые образы, hermetic-плагины → воспроизводимый вывод.
2. Идемпотентность: одна и та же сборка → одинаковые артефакты и хэши.
3. Инкрементальность: пересобираем только изменившееся (DAG/needs/matrix/affected).
4. Локальность и «тепло»: кэши рядом с раннерами/в реестре, прогрев перед пиками.
5. Явная инвалидация: ключи кэша по lockfile/файлам конфигурации и по хэшу содержимого.
6. Гигиена: TTL/`expire_in`, авто-очистка, контроль размера кэшей и артефактов.
7. Безопасность цепочки поставки: кэш ≠ мусорка для секретов; SBOM/подпись артефактов остаются обязательными.


3) Docker/OCI: быстрые образы без переcборов

Паттерны

Multi-stage (builder → runtime).
Минимальный runtime (distroless/ubi-micro, только нужные so/ca-certs).
Порядок слоев: сначала редко меняющееся (deps), потом код.
`.dockerignore`: исключайте `.git`, тесты/фикстуры, локальные кэши.
BuildKit: `cache-from/to` → общий кэш между джобами и ветками.

Пример Dockerfile (Node + pnpm)

dockerfile syntax=docker/dockerfile:1.7
FROM node:20-bookworm AS deps
WORKDIR /app
COPY pnpm-lock.yaml./
RUN corepack enable && pnpm fetch

FROM node:20-bookworm AS builder
WORKDIR /app
COPY --from=deps /root/.cache/pnpm /root/.cache/pnpm
COPY package.json pnpm-lock.yaml./
RUN corepack enable && pnpm install --offline
COPY..
RUN pnpm build

FROM gcr.io/distroless/nodejs20 AS runtime
WORKDIR /app
COPY --from=builder /app/dist./dist
USER 10001
CMD ["dist/server.js"]

BuildKit в CI (GitHub Actions)

yaml
- uses: docker/setup-buildx-action@v3
- uses: actions/cache@v4 with:
path: /tmp/.buildx-cache key: buildx-${{ github.ref }}-${{ github.sha }}
restore-keys: buildx-${{ github.ref }}-
- uses: docker/build-push-action@v6 with:
push: true tags: ${{ env.IMAGE }}
cache-from: type=gha cache-to: type=gha,mode=max

4) Языковые экосистемы: что кэшировать и как

Java/Kotlin (Maven/Gradle)

Remote cache Gradle, параллелизм, конфигурация-по-запросу.
Ключ кэша: хэш `build.gradle[.kts]` + lockfiles + `gradle-wrapper.properties`.
Публикация build cache node на объектном storage/HTTP.
Инкрементальная компиляция и тест-split по пакетам.

yaml
GitLab CI cache:
key: gradle-${CI_COMMIT_REF_SLUG}
paths: [.gradle/caches,.gradle/wrapper ]
script:
-./gradlew --build-cache --parallel build

Node.js (npm/pnpm/yarn)

Кэш локального store (`~/.npm`, `~/.cache/pnpm`), ключ по lockfile.
Nx/Turborepo remote-cache (S3/Redis) для задач (lint/test/build).
`turbo run build --cache-dir=.turbo` и «affected»-режим для монорепо.

Python (pip/Poetry)

Кэш wheels + virtualenv; ключ по `requirements.lock`/`poetry.lock`.
Сборка wheels в отдельной стадии, переиспользование между матрицами.
Для C-расширений — `pip wheel` + `auditwheel` в builder-образе.

Go

Кэш `GOMODCACHE`, `GOCACHE`; фиксируйте `GOTOOLCHAIN`/версии.
Делите шаги: `go mod download` → копия кода → `go build`.
Для больших монореп — Bazel/Bazelisk или `mage` со слоевым билдом.

Rust

`~/.cargo/registry`, `~/.cargo/git`, `target/`; sccache (удаленный/локальный).
Совместное использование кэша между ветками по `Cargo.lock`.

C/C++

ccache/sccache + ключ по флагам компилятора и версиям SDK.
Вынос toolchain в отдельный базовый образ.


5) Bazel/Nx/Turborepo: кэш задач и графа

Bazel remote cache (HTTP/Cloud) — контент-адресуемый; строгая герметичность, песочницы.
Nx/Turborepo — кэш выходов задач и «only-affected» выполнение в монорепо.
Инвалидация: зависит от входов шага (файлы/флаги/переменные).


6) Стратегии инвалидации кэша

Ключ = хэш входов: lockfiles, конфиги компиляторов, манифесты.
Мягкая инвалидация: `restore-keys` (GHA) / префиксы (GLCI).
Жесткая инвалидация: rotate namespace/ключ при критических изменениях.
Разделение слоев: deps vs sources — меняйте код без трогания тяжелых зависимостей.


7) Инкрементальные билды и матрицы

DAG/needs: запускайте зависимые джобы параллельно, не ждите последовательностей.
Paths-filter: триггер только для затронутых компонентов.
Shard тестов: по каталогам/seed, выравнивайте длительность.
Warm-pool раннеров: предварительно прогретые образы/кэши перед пиками (турниры/кампании).


8) Артефакты vs кэш: чем отличаются

Кэш: переиспользуемые входы/промежуточные результаты, «грязная» область, TTL короткий/средний.
Артефакты: финальные сборки (образы, бинарники, charts), неизменяемые, подписанные, с SBOM.
Правила: кэш чистится агрессивно, артефакты — хранятся по политике релизов.


9) Наблюдаемость, KPI и FinOps

Метрики (по пайплайну/репо):
  • Hit-rate кэша (%), Warm-start vs Cold-start time, средняя/медиана длительности стадий.
  • Cost per pipeline/job, размер кэша/артефактов, пропускная (jobs/hour).
  • Доля «affected-runs» в монорепо, пересборка без изменений (waste).
Алерты:
  • Падение hit-rate ниже порога, рост времени «build image», раздувание артефактов, промахи по SLO.

10) Безопасность кэша и supply chain

Никаких секретов в кэше/артефактах; mask vars, сканы секретов.
Pin SHA внешних actions/plugins, только доверенные runners.
Подпись контейнеров/бинарей (cosign), SBOM (CycloneDX/SPDX) и проверка на CD.
Изоляция: раздельные namespace кэша для `dev/stage/prod`, права «только чтение» для foreign branches.


11) Практические шаблоны

GitHub Actions — язык+контейнер

yaml name: ci on: [push, pull_request]
concurrency: { group: ${{ github.ref }}, cancel-in-progress: true }
jobs:
build:
runs-on: ubuntu-latest steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4 with: { node-version: '20' }
- uses: actions/cache@v4 with:
path: ~/.cache/pnpm key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- run: corepack enable && pnpm i --frozen-lockfile
- run: pnpm build
- uses: docker/build-push-action@v6 with:
tags: ${{ env.IMAGE }}
cache-from: type=gha cache-to: type=gha,mode=max

GitLab CI — Gradle remote cache

yaml variables:
GRADLE_USER_HOME: ".gradle"
cache:
key: gradle-${CI_COMMIT_REF_SLUG}
paths: [.gradle/wrapper,.gradle/caches ]
build:
stage: build script:
-./gradlew --build-cache --no-daemon build artifacts:
paths: [ "build/libs/.jar" ]
expire_in: 3 days

Jenkins — ccache/sccache

groovy pipeline {
agent { label 'cpp' }
environment { CCACHE_DIR = '/cache/ccache' }
stages {
stage('Build') {
steps {
sh 'ccache -M 10G'
sh 'cmake -B build -S. && cmake --build build -j$(nproc)'
}
}
}
post { always { sh 'ccache -s' } }
}

12) ML/данные: ускоряем тяжелые сборки

Кэш моделей/эмбеддингов/датасетов на локальных NVMe раннеров; версионирование по хэшу.
Предсборка TensorRT/ONNX движков как релиз-артефактов; повторное использование в инференсе.
Chunked-артефакты (splits) для больших моделей; TTL и отложенная очистка.


13) Чек-лист внедрения

1. Зафиксируйте lockfiles и базовые образы; включите BuildKit.
2. Разделите слои Docker: deps → код; добавьте `.dockerignore`.
3. Поднимите remote cache (Gradle/Bazel/Nx/Turbo); заведите dependency proxy.
4. Настройте кэш зависимостей в CI по lockfile; включите матрицы и `paths-filter`.
5. Введите инкрементальные билды и «affected only» в монорепо.
6. Мерьте hit-rate, warm/cold time, стоимость; выставьте алерты.
7. Включите SBOM/подпись, запретите секреты в кэше.
8. Прогревайте кэши перед пиковыми релизами; регламентируйте TTL/retention.
9. Документируйте инвалидацию кэшей и runbooks на «кэш сломан».
10. Регулярно чистите «вечные» кэши и архивируйте тяжелые артефакты.


14) Антипаттерны

Огромный Dockerfile с часто меняющимися шагами до установки deps.
Общий «вечный» кэш без ключей/TTL → флейки и мусор.
Смешивание артефактов и кэша; отсутствие подписи/SBOM.
Неприджатые версии инструментов → «кэш есть, но не повторяется».
Матрицы «на все» при каждом PR; отсутствие `concurrency.cancel`.
Единый runner без теплого кэша и без dependency proxy.


Итоги

Оптимизация сборки — это системная работа с кэшами, инкрементальностью и детерминированностью. Правильная структура Dockerfile, remote-cache для билдов, dependency proxy и дисциплина инвалидации дают быстрые, дешевые и воспроизводимые конвейеры. Добавьте наблюдаемость и правила безопасности — и ваши релизы будут частыми, стабильными и экономными.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.