Montageoptimierung und Caching
(Abschnitt: Technologie und Infrastruktur)
Kurze Zusammenfassung
Die CI/CD-Geschwindigkeit in iGaming wirkt sich direkt auf die Veröffentlichungsfrequenz, die Minutenkosten und die p99-Stabilität bei Spitzenlasten aus. Der Schlüssel sind die richtigen Caches (Abhängigkeiten, Artefakte, Containerschichten, Zwischenergebnisse der Kompilierung), inkrementelle Baugruppen und Determiniertheit. Ein „guter“ Build wird bei unveränderter Eingabe schnell wiederholt und die Cache-Behinderung ist vorhersehbar und kontrollierbar.
1) Cachekarte und was wir zwischenspeichern
Abhängigkeiten: NPM/pnpm Pakete, Pip Räder/Poesie, Maven/Gradle, Go Mode, Cargo Crates, NuGet.
Zwischenartefakte der Kompilierung: '~/.cache/pip', '~/.m2', '.gradle', '~/.cargo/registry/',' $ GOMODCACHE', 'target/',' build/', 'node _ modules/.pnpm-store'.
Container Layers: Docker Layer Cache (BuildKit/GHA Cache), Registry-basierter Cache, Multi-Stage.
Tools und SDKs: Toolchains/Microimages (JDK, Node, Python, Rustup Targets).
Mono/Polyrepo-Meta: Nx/Turborepo/Bazel Remote-Cache für Aufgaben (lint/test/build).
Testdaten und e2e-Fiktionen: DB-Snepshots, kompilierte UI-Bundles.
ML/Daten: vorbereitete Datasets, Embeddings, kompilierte Engines (TensorRT/ONNX).
2) Prinzipien der schnellen und vorhersehbaren Montage
1. Determinität: Fixieren Sie Versionen (lockfiles), Pin-Baseline-Images, Hermetic-Plugins → reproduzierbare Ausgaben.
2. Idempotenz: Derselbe Build → dieselben Artefakte und Hashes.
3. Inkrementalität: Wir bauen nur die geänderte wieder zusammen (DAG/Bedarf/Matrix/betroffen).
4. Lokalität und „Wärme“: Caches neben den Läufern/im Register, Aufwärmen vor den Spitzen.
5. Offensichtliche Behinderung: Cache-Schlüssel aus Lockfile/Konfigurationsdateien und Content-Hash.
6. Hygiene: TTL/' expire _ in', automatische Reinigung, Kontrolle der Größe von Caches und Artefakten.
7. Lieferkettensicherheit: Cache ≠ Trödel für Geheimnisse; SBOM/Artefakt-Signatur bleibt obligatorisch.
3) Docker/OCI: schnelle Bilder ohne Nachbauten
Muster
Multi-stage (builder → runtime).
Minimale Laufzeit (distroless/ubi-micro, nur benötigte so/ca-certs).
Layer-Reihenfolge: erst selten wechselnd (deps), dann Code.
„.dockerignore“: „.git“, Tests/Fixturen, lokale Caches ausschließen.
BuildKit: 'cache-from/to' → ein gemeinsamer Cache zwischen Jobs und Zweigen.
Beispiel für 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) Sprachökosysteme: Was zwischengespeichert werden soll und wie
Java/Kotlin (Maven/Gradle)
Remote Cache Gradle, Parallelität, Konfiguration-on-demand.
Cache-Schlüssel: hash 'build. gradle[.kts]` + lockfiles + `gradle-wrapper. properties`.
Build-Cache-Node auf Objektspeicher/HTTP veröffentlichen.
Inkrementelle Kompilierung und Testsplit nach Paketen.
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)
Lokaler Store-Cache ('~/.npm', '~/.cache/pnpm'), Schlüssel durch Lockfile.
Nx/Turborepo Remote-Cache (S3/Redis) für Aufgaben (lint/test/build).
'turbo run build --cache-dir = .turbo' und 'affected' -Modus für Monorepos.
Python (pip/Poetry)
Cache wheels + virtualenv; Schlüssel durch 'requirements. lock`/`poetry. lock`.
Montage der Räder in einem separaten Schritt, Wiederverwendung zwischen den Matrizen.
Für C-Erweiterungen steht 'pip wheel' + 'auditwheel' im Builder-Image.
Go
Кэш `GOMODCACHE`, `GOCACHE`; fix' GOTOOLCHAIN '/Versionen.
Teilen Sie die Schritte „go mod download“ → eine Kopie des Codes → „go build“.
Für große Monoreps - Bazel/Bazelisk oder 'mage' mit Layer-Build.
Rust
`~/.cargo/registry`, `~/.cargo/git`, `target/`; sccache (remote/lokal).
Teilen Sie den Cache zwischen den Zweigen durch 'Cargo. lock`.
C/C++
ccache/sccache + Schlüssel für Compiler-Flags und SDK-Versionen.
Nehmen Sie die Toolchain in ein separates Basis-Image.
5) Bazel/Nx/Turborepo: Task- und Graph-Cache
Bazel Remote Cache (HTTP/Cloud) - inhaltsadressierbar; strenge Dichtheit, Sandkästen.
Nx/Turborepo - Cache von Task-Ausgaben und „nur-betroffen“ Ausführung in Monorepos.
Behinderung: abhängig von Schritteingaben (Dateien/Flags/Variablen).
6) Cache-Behinderungsstrategien
Schlüssel = Hash der Eingaben: lockfiles, Compiler-Configs, Manifeste.
Leichte Behinderung: 'restore-keys' (GHA )/Präfixe (GLCI).
Harte Behinderung: Rotate Namespace/Schlüssel bei kritischen Veränderungen.
Layer-Split: deps vs sources - Ändern Sie den Code, ohne schwere Abhängigkeiten zu berühren.
7) Inkrementelle Bilder und Matrizen
DAG/needs: Führen Sie abhängige Jobs parallel aus, warten Sie nicht auf Sequenzen.
Pfade-Filter: Trigger nur für betroffene Komponenten.
Shard-Tests: durch Kataloge/Samen, richten Sie die Dauer.
Warm-Pool der Läufer: vorgewärmte Bilder/Caches vor den Spitzen (Turniere/Kampagnen).
8) Artefakte vs Cache: Was ist der Unterschied
Cache: Überbeanspruchte Eingänge/Zwischenergebnisse, „schmutziger“ Bereich, TTL kurz/mittel.
Artefakte: finale Builds (Images, Binaries, Charts), unveränderlich, signiert, mit SBOM.
Regeln: Der Cache wird aggressiv gesäubert, Artefakte werden gemäß der Veröffentlichungsrichtlinie gespeichert.
9) Beobachtbarkeit, KPIs und FinOps
Metriken (nach Pipeline/Repo):- Hit-Rate des Caches (%), Warm-Start vs Cold-Start-Zeit, mittlere/mediane Dauer der Stufen.
- Kosten pro Pipeline/Job, Cache-Größe/Artefakte, Durchsatz (Jobs/Stunde).
- Anteil der "affected-runs' im Monorepo, Nachbau unverändert (waste).
- Die Hit-Rate fällt unter die Schwelle, die „Build-Image“ -Zeit steigt, Artefakte werden aufgeblasen, SLO-Fehler.
10) Cache und Supply Chain Sicherheit
Keine Geheimnisse im Cache/Artefakte; Maske vars, Scans von Geheimnissen.
Pin SHA externe Aktionen/Plugins, nur vertrauenswürdige Läufer.
Signatur von Containern/Binären (cosign), SBOM (CycloneDX/SPDX) und Überprüfung auf CD.
Isolation: separater Namespace-Cache für 'dev/stage/prod', schreibgeschützte Rechte für ausländische Filialen.
11) Praktische Vorlagen
GitHub Actions - Sprache + Container
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/Daten: Wir beschleunigen schwere Baugruppen
Cache von Modellen/Embeddings/Datasets auf lokalen NVMe-Läufern; Versionierung nach Hash.
Vormontage TensorRT/ONNX Motoren als Release-Artefakte; Wiederverwendung in der Inferenz.
Chunked-Artefakte (Splits) für große Modelle; TTL und verzögerte Reinigung.
13) Checkliste Umsetzung
1. Fixieren Sie lockfiles und grundlegende Bilder; Aktivieren Sie BuildKit.
2. Trennen Sie die Docker-Ebenen: deps → Code; „.dockerignore“ hinzufügen.
3. Heben Sie den Remote-Cache an (Gradle/Bazel/Nx/Turbo); Starten Sie dependency proxy.
4. Konfigurieren Sie den Abhängigkeitscache in der CI durch Lockfile; Matrizen und 'Pfade-Filter' einschließen.
5. Geben Sie inkrementelle Bilds und „nur betroffen“ in Monorepos ein.
6. Messen Sie Hit-Rate, warm/kalte Zeit, Kosten; Stellen Sie die Alerts auf.
7. SBOM/Signatur einschalten, Geheimnisse im Cache verbieten.
8. Caches vor Peak-Releases aufwärmen; reglementieren Sie die TTL/retention.
9. Dokumentieren Sie die Behinderung von Caches und Runbooks mit „Cache gebrochen“.
10. Reinigen Sie regelmäßig die „ewigen“ Caches und archivieren Sie schwere Artefakte.
14) Antipatterns
Riesige Dockerfile mit oft wechselnden Schritten vor der Installation von deps.
Gemeinsamer „ewiger“ Cache ohne Schlüssel/TTL → Flakes und Müll.
Mischen von Artefakten und Cache; keine Signatur/SBOM.
Unappetitliche Versionen der Tools → „Es gibt einen Cache, aber er wiederholt sich nicht“.
Matrizen „für alles“ bei jeder PR; Mangel an 'concurrency. cancel`.
Ein einzelner Runner ohne warmen Cache und ohne Abhängigkeitsproxy.
Ergebnisse
Build-Optimierung ist die Systemarbeit mit Caches, Inkrementalität und Determinanz. Die richtige Struktur von Dockerfile, Remote-Cache für Bilds, Dependency Proxy und Disability Disciplination ergeben schnelle, günstige und reproduzierbare Pipelines. Fügen Sie Beobachtbarkeit und Sicherheitsregeln hinzu - und Ihre Veröffentlichungen werden häufig, stabil und wirtschaftlich sein.