Smarter CI/CD
Ausgangssituation
Viele CI/CD-Pipelines folgen einem einfachen Prinzip:
Bei jedem Commit wird einfach alles gebaut.
Das funktioniert. Aber es ist:
-
langsam
-
ressourcenintensiv
-
unnötig
Gerade bei unterschiedlichen Ziel-Artefakten, wie auch bei meinem persönlichen Profil (README, Architektur, Website), führt das schnell dazu, dass bei jeder kleinen Änderung die komplette Pipeline läuft – obwohl sich vielleicht nur eine einzige Datei geändert hat.
Zielbild
Die Idee ist einfach:
Build only what changed. Deploy only what matters.
Das bedeutet konkret:
-
Nur die Artefakte bauen, die wirklich betroffen sind
-
Nur deployen, wenn sich tatsächlich etwas geändert hat
-
Die Build-Umgebung reproduzierbar und stabil halten
-
Ressourcenverbrauch reduzieren (greenIT)
Lösungsstrategie
Die Pipeline basiert auf vier zentralen Bausteinen.
1. Immutable Build Environment
Die gesamte Build-Umgebung wird in ein Docker-Image gepackt.
-
Das Image wird über einen Hash versioniert
-
Grundlage sind
Dockerfileund.dockerignore -
Es wird nur neu gebaut, wenn sich diese Dateien ändern
sha256sum Dockerfile .dockerignore | sha256sum | cut -c1-12
Vorteile:
-
reproduzierbare Builds
-
keine “works on my machine”-Probleme
-
klare Trennung von Build-Logik und Pipeline
Zusätzlich wird ein latest-Tag verwendet, um Docker Layer Cache zu ermöglichen.
2. Change Detection
Statt blind alles zu bauen, wird zuerst analysiert, was sich geändert hat.
Dafür wird ein Pfad-basierter Filter verwendet:
filters:
readme:
- 'README.adoc'
- 'profile/**'
architecture:
- 'docs/**'
site:
- 'profile/**'
Damit lassen sich Änderungen in Kategorien einteilen:
-
README
-
Architektur
-
Website
3. Conditional Build Execution
Auf Basis der erkannten Änderungen wird der Build dynamisch zusammengestellt.
CMD="./gradlew --no-daemon"
if [ "$README_CHANGED" == "true" ]; then
CMD="$CMD buildReadme"
fi
if [ "$ARCH_CHANGED" == "true" ]; then
CMD="$CMD buildArchitecture"
fi
if [ "$SITE_CHANGED" == "true" ]; then
CMD="$CMD buildSite"
fi
Wenn keine relevanten Änderungen vorliegen:
Nothing to build
→ Die Pipeline endet frühzeitig.
4. Artifact-Based Deployment
Die Pipeline trennt strikt zwischen:
-
Build
-
Deploy
Ablauf:
-
Artefakte bauen
-
Artefakte speichern
-
Deployment in separatem Schritt
Deploy-Ziele:
-
GitHub Profil (README)
-
GitLab Profil (README)
-
GitHub Pages (Architektur)
-
persönliche Domain (Site)
Vorteil:
-
Build und Deployment sind entkoppelt
-
Deploy kann unabhängig wiederholt werden
5. Docker Layer Caching
Um Build-Zeiten zu reduzieren, wird ein Registry-basierter Cache genutzt:
--cache-from=type=registry,ref=image:latest
--cache-to=type=registry,ref=image:latest,mode=max
Das reduziert insbesondere:
-
Dependency Downloads
-
Package Installationen
Ergebnis
Die Pipeline hat sich dadurch deutlich verändert:
| Vorher | Nachher |
|---|---|
Alles wird immer gebaut |
Nur relevante Teile werden gebaut |
Lange Laufzeiten |
Deutlich schnellere Builds |
Hoher Ressourcenverbrauch |
Effizientere Nutzung (greenIT) |
Kaum Struktur |
Klare Trennung von Verantwortlichkeiten |
Trade-offs
Natürlich hat der Ansatz auch Nachteile:
-
höhere Komplexität in der Pipeline
-
Pflege der Pfad-Filter notwendig
-
etwas mehr Initialaufwand
In der Praxis überwiegen jedoch die Vorteile deutlich.
Fazit
CI/CD sollte nicht nur funktionieren – sondern mitdenken.
Eine Pipeline, die versteht, was sich geändert hat, ist:
-
schneller
-
effizienter
-
nachhaltiger
-
robuster
Und ganz nebenbei auch deutlich angenehmer im Alltag.
Ausblick
Mögliche nächste Schritte:
-
Parallelisierung der Builds
-
Preview Deployments für Pull Requests
-
Automatisches Aufräumen alter Docker Images
-
Metriken zur Pipeline-Performance
Die Grundlage dafür ist bereits gelegt.