Von 7 Minuten auf 13 Sekunden: Warum ich mein eigenes CI/CD-Tool gebaut habe
GitHub Actions ist ein fantastisches Tool. Die Integration in GitHub ist nahtlos, die Marketplace-Actions decken fast jeden Use Case ab, und für die meisten Projekte reicht es vollkommen aus. Trotzdem habe ich mein eigenes CI/CD-Tool geschrieben. Nicht weil GitHub Actions schlecht ist — sondern weil es für meine Anforderungen zu langsam war.
Das Problem mit GitHub Actions
Wer schon mal eine GitHub Actions Pipeline optimiert hat, kennt das Gefühl: Man cached Dependencies, parallelisiert Jobs, nutzt kleinere Base-Images — und am Ende wartet man trotzdem Minuten, bis der Build durch ist.
Bei manchen Projekten sah das so aus: Ursprüngliche Build-Zeiten von 30-40 Minuten. Nach intensiver Optimierung — Docker Layer Caching, Dependency Caching, Build-Matrix-Tuning — konnte ich die Zeiten auf 5-7 Minuten drücken. Klingt nach einem Erfolg, fühlt sich aber trotzdem langsam an, wenn man gerade schnell einen Fix deployen will.
Das Grundproblem dabei ist architekturbedingt und lässt sich nicht wegoptimieren:
Jeder Build startet bei Null. GitHub Actions provisioniert für jeden Workflow-Run eine frische VM oder einen Container. Das bedeutet: Go muss installiert werden. Node muss installiert werden. Docker muss gestartet werden. Dependencies müssen heruntergeladen werden. Jedes. Einzelne. Mal. Caching hilft, aber das Entpacken und Wiederherstellen eines Caches kostet ebenfalls Zeit.
Self-Hosted Runner helfen kaum. Man könnte denken, dass eigene Runner das Problem lösen. Tun sie aber nur bedingt. Die Actions selbst installieren trotzdem Tools, laden Dependencies, und der Overhead des Runners bleibt.
Lokales Testen ist nicht möglich. Will man eine Pipeline lokal testen, braucht man Third-Party-Tools wie act, die GitHub Actions nur annähernd nachbilden. Die Pipeline-Syntax ist an GitHub gebunden — man kann sie nicht einfach auf der eigenen Maschine ausführen.
Der Ansatz: Was wäre, wenn die Tools schon da wären?
Die Idee hinter cictl ist simpel: Wenn der größte Zeitfresser das Installieren von Tools und das Bootstrapping der Umgebung ist, dann eliminiere ich genau das.
cictl ist ein leichtgewichtiges CI/CD-Tool, das als dauerhafter Runner läuft. Die Tools — Go, Node, Docker, Podman — sind vorinstalliert und sofort verfügbar. Kein Download, kein Entpacken, kein Setup. Der Build startet und die erste Zeile Code kompiliert sofort.
Das Ergebnis war sofort spürbar: Dieselbe Pipeline, die bei GitHub Actions nach Optimierung 5-7 Minuten brauchte, lief mit cictl in 30-50 Sekunden. Nach weiteren Anpassungen bin ich jetzt bei 13-16 Sekunden für einen kompletten Build inklusive Container-Image und Push in die Registry.
Wo die Zeit gespart wird
Die Zeitersparnis kommt aus mehreren Faktoren:
Kein Tool-Setup. Go, Docker, Node — alles ist bereits installiert und konfiguriert. Das Docker-Image, in dem der Runner läuft, enthält genau die Tools, die für die jeweiligen Projekte gebraucht werden. Nicht mehr, nicht weniger.
Persistente Umgebung. Der Runner läuft dauerhaft. Go-Module sind im Cache, Docker-Layer sind lokal vorhanden, npm-Packages müssen nicht jedes Mal neu heruntergeladen werden. Die Umgebung wärmt sich mit der Zeit auf.
Kein Orchestrierungs-Overhead. Es gibt keine VM-Provisionierung, kein Container-Scheduling für den Runner selbst, keinen Checkout-Action-Overhead. Ein Git-Webhook kommt rein, der Code wird gepullt, der Build startet.
Schlanke Pipeline-Definition. Keine marketplace Actions mit eigenem Setup. Die .cictl.yaml beschreibt direkt, was passieren soll:
name: my-app
version:
strategy: semver
source: conventional-commits
build:
container:
image: ghcr.io/org/my-app
tags:
- "v{{.Version}}"
- latest
push: true
on:
push:
branches:
- main
jobs:
test:
name: Tests
runs-on: local
steps:
- name: Test
run: go test ./...
lint:
name: Lint
runs-on: local
steps:
- name: Vet
run: go vet ./...
Kein actions/checkout@v4, kein actions/setup-go@v5, kein docker/login-action@v3. Nur die eigentlichen Build-Schritte.
Setup und Einrichtung
cictl lässt sich auf zwei Arten betreiben: lokal auf dem eigenen Rechner oder als Runner im Kubernetes-Cluster.
Lokale Ausführung
Pipeline lokal ausführen — etwas, das mit GitHub Actions schlicht nicht geht:
cictl run -f .cictl.yaml
Das war's. cictl liest die Pipeline, löst die Version auf, führt die Jobs aus. Auf der eigenen Maschine, mit den lokal installierten Tools.
Runner im Cluster
Für den dauerhaften Betrieb wird der Runner mit einer Konfigurationsdatei gestartet:
repos:
- url: https://github.com/org/repo.git
branch: main
webhook:
enabled: true
listen: ":8080"
secret: "${WEBHOOK_SECRET}"
store:
type: redis
Der Runner überwacht die konfigurierten Repositories, reagiert auf GitHub/GitLab-Webhooks, und stellt ein Web-Dashboard mit Live-Build-Logs bereit. Die Builds laufen automatisch — Push auf main, Webhook kommt rein, Build startet, Image wird gebaut und gepusht.
Mehrere Runner-Instanzen teilen sich den State über Redis, inklusive Session-Daten für die optionale OIDC-Authentifizierung des Dashboards.
Versionierung inklusive
Ein Feature, das ich nicht mehr missen möchte: Automatische semantische Versionierung über Conventional Commits. Kein manuelles Tag-Setzen, kein Versions-Bumping in Dateien. cictl liest die Commit-History, bestimmt die nächste Version, taggt das Repository und injiziert die Version als Variable in den Build.
Ein feat: Commit bumpt die Minor-Version, ein fix: die Patch-Version, ein Breaking Change die Major-Version. Das passiert automatisch, bei jedem Build.
Fazit
GitHub Actions bleibt ein gutes Tool für viele Teams und Projekte. Aber wenn Build-Geschwindigkeit wirklich zählt — wenn der Unterschied zwischen 7 Minuten und 13 Sekunden den Entwicklungsflow verändert — dann lohnt es sich, die CI/CD-Pipeline näher an die eigene Infrastruktur zu bringen.
cictl ist kein GitHub-Actions-Ersatz für alle. Es ist ein spezialisiertes Tool für Teams und Entwickler, die maximale Build-Performance wollen und bereit sind, ihre Runner selbst zu betreiben. Dafür bekommt man Builds, die sich anfühlen wie lokale Ausführung — weil sie es im Grunde auch sind.
| GitHub Actions (optimiert) | cictl Runner | |
|---|---|---|
| Blog-Build | 5-7 min | 13-16 sek |
| Tool-Installation | Jedes Mal | Einmalig vorinstalliert |
| Lokale Ausführung | Nicht nativ | cictl run |
| Setup-Overhead | VM/Container pro Run | Dauerhafter Runner |