Hook – Warum ich mir die Hände verbrenne, wenn ich wieder YAML schreibe
Ich erinnere mich noch an den Moment, als ich in einem Teammeeting das Wort "YAML" hörte und fast sofort das Gefühl bekam, in einen Klimazwerg verwandelt zu werden – nur weil ich die nächste Stunde damit verbringen musste, ein verschachteltes Build‑File zu debuggen. Drei Ebenen steps: → script: → env: und das ganze Ergebnis kam trotzdem nie ganz ohne Überraschungen heraus. Während das heute noch ein Schlepptau für viele ist, hat mich Dagger.io aus dem Labyrinth geführt. In diesem Artikel zeige ich, warum das Paradigma Pipelines als Code ein Game‑Changer ist, wie Dagger das ganze Konzept ohne YAML realisiert und welche Stolperfallen Sie vermeiden sollten.
1. Von YAML zu echter Programmiersprache – das Kernkonzept von Dagger
Erklärung
Dagger ist ein Open‑Source‑Framework, das CI/CD‑Pipelines als erstklassige Code‑Komponenten behandelt. Anstatt Declaratives YAML zu schreiben, definiert man den Build‑ und Deploy‑Flow in einer echten Programmiersprache – derzeit Go, Python und TypeScript. Das bringt drei sofortige Vorteile:
- Typ‑Safety – Der Compiler prüft bereits beim Schreiben, ob ein Befehl existiert, ob Parameter passen und ob Rückgaben korrekt behandelt werden.
- IDE‑Unterstützung – Autocomplete, Refactoring und Linting funktionieren wie bei jedem anderen Code‑Projekt.
- Wiederverwendbare Funktionen – Logik kann in Bibliotheken ausgelagert und über Paket‑Managern wiederverwendet werden.
Beispiel 1 – Minimaler Dagger‑Workflow in Go
package main
import (
"context"
"dagger.io/dagger"
)
func main() {
// 1️⃣ Dagger Client initialisieren – das ist das Pendant zu "docker login"
client, err := dagger.Connect(context.Background())
if err != nil { panic(err) }
defer client.Close()
// 2️⃣ Basis-Image auswählen
node := client.Container().From("node:20-alpine")
// 3️⃣ Quellcode einbinden
src := client.Host().Directory("./my-app")
node = node.WithDirectory("/src", src).WithWorkdir("/src")
// 4️⃣ Build‑Schritt ausführen
node = node.WithExec([]string{"npm", "install"}).WithExec([]string{"npm", "run", "build"})
// 5️⃣ Artefakt exportieren
_, err = node.Export(context.Background(), ".out")
if err != nil { panic(err) }
}
Hier sehen Sie, dass jede Zeile ein echter Go‑Befehl ist – keine versteckten Schlüsselwörter, keine -‑Syntax, die plötzlich einen Syntaxfehler wirft, weil ein Leerzeichen fehlt. Der Compiler weist Sie sofort darauf hin, wenn ein Befehl nicht existiert.
Einschätzung
Der psychologische Gewinn ist enorm: Entwickler fühlen sich nicht mehr wie „YAML‑Jäger“, sondern wie reguläre Software‑Ingenieure. Das reduziert die Lernkurve und erhöht die Code‑Qualität – weil das gleiche Werkzeug, das Sie zum Schreiben von Applikationslogik verwenden, jetzt auch Ihre Deploy‑Logik schreibt.
2. Praktische Dagger‑Features, die YAML nie bieten konnte
Erklärung
Dagger liefert ein container‑basiertes Abstraktionsmodell, das automatisch Caching, Parallelisierung und Secret‑Management integriert. Statt in jedem Schritt eigene Skripte zu schreiben, nutzen Sie die integrierten Methoden:
-
WithExecführt Befehle im Container aus. -
CacheVolumedefiniert persistente Volumes für Zwischenergebnisse. -
Secretimportiert sensible Daten ohne sie im Git zu speichern.
Beispiel 2 – Caching von Node‑Modules mit Dagger
cache := client.CacheVolume("node-modules")
node = node.WithMountedCache("/src/node_modules", cache)
node = node.WithExec([]string{"npm", "install"}) // nutzt das Cache‑Volume
Durch das explizite Caching wird das zweite Durchlaufen des Pipelines signifikant schneller – und das ohne separate actions/cache‑Step‑Definition, wie sie in GitHub Actions üblich ist.
Beispiel 3 – Secrets sicher einbinden
mySecret := client.Secret().File("./secrets/api_key.txt")
node = node.WithSecretVariable("API_KEY", mySecret)
node = node.WithExec([]string{"bash", "-c", "curl -H 'Authorization: Bearer $API_KEY' https://api.example.com"})
Die Secret‑API sorgt dafür, dass das Geheimnis nie im Klartext ins Image gelangt, sondern zur Laufzeit im Container injiziert wird – analog zu Docker‑Secrets, jedoch komplett code‑seitig.
Einschätzung
Durch diese integrierten Bausteine wird das gesamte CI‑Setup modularer und wartbarer. Keine separate YAML‑Datei für Caching, keine extra‑Tool‑Wrapper – alles wird über die Dagger‑API orchestriert.
3. Wie Sie Dagger in Ihre bestehende Git‑Workflow‑Umgebung einbinden
Erklärung
Die meisten Teams nutzen bereits Git‑Hooks oder Plattform‑CI (GitHub Actions, GitLab CI). Dagger lässt sich nahtlos dort einbinden, indem Sie ein kleines Wrapper‑Script benutzen, das Ihren Dagger‑Code ausführt. So bleibt die bestehende Infrastruktur bestehen, ohne dass Sie komplett umziehen.
Beispiel 4 – GitHub Action, die Dagger ausführt
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Dagger CLI
run: |
curl -L https://dl.dagger.io/dagger/install.sh | sudo sh
- name: Run Dagger pipeline
run: |
dagger run go run ./ci/pipeline.go
Der Aufruf dagger run go run ./ci/pipeline.go startet Ihren Go‑basierten Dagger‑Workflow. Der Rest des CI‑Systems bleibt unverändert.
Beispiel 5 – Lokale Entwicklung mit dagger develop
# Startet einen interaktiven Container, in dem Sie Befehle testen
dagger develop
dagger develop spinnt einen temporären Container auf, in dem Sie Ihre Pipeline Schritt für Schritt ausprobieren – ähnlich wie docker run -it. Das reduziert die „It‑Works‑On‑My‑Machine“-Problematik drastisch.
Einschätzung
Die Integration ist leichtgewichtig und erfordert keine komplette Migration. Sie können Dagger zunächst in einem einzelnen Projekt testen und dann nach und nach weitere Pipelines migrieren.
4. Häufige Fehler – Was schiefgeht, wenn man Dagger ohne Vorbereitung einsetzt
| Fehler | Ursache | Korrektur |
|---|---|---|
Unvollständige go.mod‑Datei |
Beim Erstellen des Dagger‑Clients fehlt das Modul‑Setup, weshalb dagger.Connect fehlschlägt. |
go mod init example.com/my-pipeline && go get dagger.io/dagger ausführen. |
Forgotten client.Close() |
Ressourcenlecks im CI‑Runner, weil der Dagger‑Client nicht geschlossen wird. | Immer defer client.Close() nach dagger.Connect einbauen. |
| Caching‑Volume nicht gemountet | Build‑Schritt wird jedes Mal neu ausgeführt, weil das Cache‑Volume fehlt. |
node = node.WithMountedCache("/src/node_modules", cache) hinzufügen. |
| Secrets im Repository gesichert | Ein Entwickler checkt api_key.txt ein, weil das Secret‑API nicht richtig benutzt wurde. |
Verwenden Sie client.Secret().File(...) und .gitignore das Datei‑Path. |
Verwechslung von Kontext und client |
WithExec wird auf einem falschen Container‑Instanz‑Objekt aufgerufen. |
Jede Transformation (From, WithDirectory etc.) gibt ein neues Container‑Objekt zurück – stets weiterreichen. |
Warum diese Fehler häufig sind
Der Hauptgrund ist, dass Entwickler aus der YAML‑Welt kommen und plötzlich vollwertigen Code schreiben müssen. Das bedeutet, dass sie plötzlich an Dinge denken müssen, die in YAML implizit sind (z. B. Scope‑Management, Variable‑Lebensdauer). Ein kurzer Code‑Review und das Einführen von Linters (z. B. golangci-lint) helfen enorm dabei, diese Stolperfallen früh zu erkennen.
5. Fazit – Der nächste Schritt zu einer YAML‑freien CI/CD‑Strategie
Dagger.io zeigt, dass Pipelines nicht länger als deklarative Text‑Dateien existieren müssen. Sie werden zu erstklassigem Code, der von den gleichen Werkzeugen geprüft, getestet und versioniert wird wie Ihre Anwendung. Das Ergebnis: weniger Fehler, schnellere Builds und ein nachhaltigeres DevOps‑Ökosystem.
Mein konkreter Handlungsaufruf:
- Installieren Sie lokal
dagger(curl -L https://dl.dagger.io/dagger/install.sh | sudo sh). - Erstellen Sie ein neues Verzeichnis
ci/und legen Sie dort einepipeline.gomit dem Minimalbeispiel aus Abschnitt 1 an. - Fügen Sie einen GitHub‑Action‑Step ein, der
dagger run go run ./ci/pipeline.goausführt. - Beobachten Sie das Caching‑Verhalten – passen Sie
CacheVolumenach Bedarf an. - Sobald das funktioniert, refaktorieren Sie Ihre bestehenden YAML‑Jobs Stück für Stück in Dagger‑Funktionen.
Damit haben Sie den ersten, entscheidenden Stein für ein YAML‑freies, Code‑zentrisches CI/CD‑System gelegt. Die Zukunft ist da – nutzen Sie sie, bevor Ihre Konkurrenz es tut.
Top comments (0)