Ratgeber · best practices
YAML in Konfiguration und DevOps: Docker, Kubernetes, CI
YAML prägt die DevOps-Welt: Docker Compose, Kubernetes-Manifeste, GitHub Actions und Ansible setzen darauf. Warum sich YAML dort durchgesetzt hat, wie die Dateien aufgebaut sind und worauf du bei der Pflege achten musst.
Wenn du dich mit Containern, Deployments oder Continuous Integration beschäftigst, kommst du an YAML nicht vorbei. Docker Compose, Kubernetes, GitHub Actions und Ansible setzen alle auf dieses Format. In diesem Ratgeber erfährst du, warum sich YAML in der DevOps-Welt durchgesetzt hat, wie die typischen Dateien aufgebaut sind und wo die Stolperfallen in der Praxis liegen.
Warum YAML in DevOps so verbreitet ist
YAML hat sich in der Infrastruktur-Welt aus mehreren Gründen durchgesetzt. Der wichtigste ist die Lesbarkeit: Eine Konfigurationsdatei soll nicht nur von Maschinen verarbeitet, sondern auch von Menschen verstanden und bearbeitet werden. YAML verzichtet auf geschweifte Klammern und Anführungszeichen, wo es geht, und nutzt stattdessen Einrückung zur Strukturierung. Das Ergebnis liest sich fast wie eine strukturierte Notiz.
Ein zweiter Punkt sind Kommentare. Anders als JSON erlaubt YAML Kommentare mit dem Doppelkreuz (#). Gerade in Konfigurationsdateien ist das Gold wert, denn du kannst direkt neben einer Einstellung erklären, warum ein Wert so gewählt wurde oder was passiert, wenn man ihn ändert.
Der dritte Grund ist die Zusammenarbeit über Git. YAML-Dateien produzieren saubere, zeilenweise Diffs. Wenn du in einem Pull-Request nur einen Port änderst, ist genau diese eine Zeile im Diff sichtbar. Das macht Code-Reviews von Infrastruktur-Änderungen deutlich angenehmer, als wenn man eine minifizierte JSON-Zeile vergleichen müsste. Die Grundlagen der Syntax haben wir dir im Ratgeber YAML-Syntax-Grundlagen im Detail aufbereitet.
Dazu kommt ein Punkt, der oft unterschätzt wird: Infrastruktur wird heute als Code behandelt. Dieser Ansatz heißt Infrastructure as Code und bedeutet, dass die komplette Konfiguration eines Systems in Textdateien liegt, die versioniert, geprüft und wiederholbar angewendet werden. YAML ist dafür ideal, weil es maschinenlesbar und trotzdem für Menschen zugänglich bleibt. Du kannst denselben Cluster morgen aus derselben Datei neu aufbauen, und das Ergebnis ist identisch. Diese Reproduzierbarkeit ist der eigentliche Gewinn: Nicht mehr ein Administrator, der Befehle von Hand eintippt und sich an Details nicht mehr erinnert, sondern eine Datei, die den Zustand vollständig beschreibt.
Docker Compose
Docker Compose beschreibt eine Anwendung, die aus mehreren Containern besteht, in einer einzigen Datei (compose.yaml oder docker-compose.yml). Der zentrale Block ist services. Darunter definierst du jeden Dienst mit seinem Image, den Ports und den Volumes.
services:
web:
image: nginx:1.27
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
depends_on:
- api
api:
image: node:22-alpine
environment:
NODE_ENV: production
PORT: "3000"
volumes:
- ./api:/app
Die Struktur ist selbsterklärend: web und api sind zwei Dienste. Bei ports steht links der Port auf deinem Host, rechts der Port im Container. Achte darauf, dass Port-Angaben in Anführungszeichen stehen. Der Grund folgt weiter unten bei den typischen Fehlern. volumes verbinden ein Verzeichnis von deinem Rechner mit einem Pfad im Container, das :ro am Ende macht das Volume schreibgeschützt.
Interessant ist auch das Feld depends_on. Es sagt Docker Compose, dass der Dienst web erst starten soll, wenn api bereitsteht. Solche Abhängigkeiten sauber zu beschreiben, ist einer der Vorteile gegenüber losen Shell-Skripten, in denen die Reihenfolge oft nur implizit über die Zeilenfolge geregelt ist. Die Umgebungsvariablen unter environment zeigen zusätzlich, wie du Werte in den Container reichst, ohne sie fest ins Image zu backen. Genau diese Trennung von Anwendung und Konfiguration ist ein Kernprinzip moderner Container-Anwendungen, und YAML macht sie an einer zentralen Stelle sichtbar.
Kubernetes-Manifeste
Kubernetes geht einen Schritt weiter und beschreibt ganze Cluster-Objekte als YAML. Jedes Manifest folgt derselben Grundstruktur mit vier Kernfeldern: apiVersion (welche API-Gruppe und Version), kind (welcher Objekttyp), metadata (Name, Labels, Namespace) und spec (die eigentliche Wunsch-Definition).
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
Dieses Manifest sagt Kubernetes: Betreibe drei Kopien (replicas: 3) eines Nginx-Containers. Der selector verbindet das Deployment mit den Pods, die über template erzeugt werden. Kubernetes vergleicht diesen Soll-Zustand laufend mit dem Ist-Zustand im Cluster und gleicht Abweichungen automatisch aus. Genau deshalb ist die Deklaration in YAML so mächtig: Du beschreibst, was du willst, nicht die einzelnen Schritte dorthin.
Manifeste können lang und verschachtelt werden. Es ist üblich, mehrere Objekte durch die YAML-Trennlinie --- in einer Datei zu bündeln, etwa ein Deployment und den zugehörigen Service. Diese Trennlinie ist übrigens ein YAML-Standardfeature: Sie markiert den Beginn eines neuen Dokuments innerhalb derselben Datei. Werkzeuge wie kubectl verarbeiten dann alle Dokumente nacheinander.
Gerade bei Kubernetes merkst du schnell, warum Kommentare so wertvoll sind. Ein Manifest mit dreißig Zeilen spec ist ohne Erklärung schwer zu durchdringen. Ein kurzer Kommentar wie # 3 Replicas für Ausfallsicherheit, nicht für Last neben dem Feld hilft dem nächsten Menschen, der die Datei anfasst, enorm. In der Praxis wachsen diese Manifeste stark, weshalb Teams oft zu Werkzeugen wie Helm oder Kustomize greifen, die YAML-Vorlagen mit Variablen füllen. Der zugrunde liegende Baustein bleibt aber immer das YAML-Manifest.
GitHub Actions und CI
In Continuous Integration beschreibt YAML, welche Schritte automatisch bei einem Push oder Pull-Request ablaufen. Bei GitHub Actions liegen diese Workflows unter .github/workflows/. Die Struktur besteht aus einem Auslöser (on), einem oder mehreren jobs und darunter den einzelnen steps.
name: CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Code auschecken
uses: actions/checkout@v4
- name: Node einrichten
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Abhängigkeiten installieren
run: npm ci
- name: Tests ausführen
run: npm test
Jeder step ist entweder eine fertige Action (uses) oder ein Shell-Kommando (run). Die Reihenfolge in der Liste bestimmt die Reihenfolge der Ausführung. Auch hier gilt: Die Node-Version steht in Anführungszeichen ("22"), damit sie nicht als Zahl interpretiert wird und dabei zum Beispiel eine Version wie 2.10 fälschlich zu 2.1 verkürzt wird.
Das gleiche Grundmuster findest du bei GitLab CI in der .gitlab-ci.yml und bei vielen anderen CI-Systemen wieder. Wer einmal verstanden hat, wie Jobs und Steps als YAML-Listen aufgebaut sind, kann sich in ein neues System schnell einlesen. Die Konzepte übertragen sich, nur die Feldnamen unterscheiden sich. Achte beim Bearbeiten von Workflows besonders auf die Einrückungstiefe, denn ein Step, der versehentlich eine Ebene zu weit links oder rechts steht, gehört plötzlich zum falschen Job oder wird gar nicht erkannt.
Ansible-Playbooks
Ansible nutzt YAML, um Server-Konfigurationen zu automatisieren. Ein Playbook ist eine Liste von Tasks, die auf definierten Hosts ausgeführt werden. Jeder Task ruft ein Modul auf, etwa zum Installieren eines Pakets oder Starten eines Dienstes.
- name: Webserver einrichten
hosts: webservers
become: true
tasks:
- name: Nginx installieren
ansible.builtin.apt:
name: nginx
state: present
- name: Nginx starten
ansible.builtin.service:
name: nginx
state: started
Das Prinzip ist dasselbe wie bei den anderen Werkzeugen: Du beschreibst den gewünschten Zustand (state: present, state: started), und Ansible sorgt dafür, dass er erreicht wird. Auch das ist deklarativ und dadurch gut nachvollziehbar. Ein Task wird nur dann ausgeführt, wenn der Ist-Zustand vom Soll-Zustand abweicht. Dieses Verhalten nennt man Idempotenz: Du kannst das Playbook zehnmal laufen lassen, und beim ersten Mal wird Nginx installiert, bei den folgenden Läufen passiert nichts mehr, weil der Zustand bereits stimmt. Das macht die Automatisierung sicher, weil ein versehentlicher Zweitlauf keinen Schaden anrichtet.
Werkzeuge im Überblick
| Werkzeug | Wofür YAML dort genutzt wird |
|---|---|
| Docker Compose | Definition von Multi-Container-Anwendungen (Services, Ports, Volumes, Netzwerke) |
| Kubernetes | Cluster-Objekte wie Deployments, Services und ConfigMaps als deklarative Manifeste |
| GitHub Actions | CI/CD-Workflows mit Auslösern, Jobs und einzelnen Ausführungsschritten |
| Ansible | Playbooks zur Server-Automatisierung (Pakete, Dienste, Dateien) |
| GitLab CI | Pipeline-Definition in der .gitlab-ci.yml mit Stages und Jobs |
Typische Fehler in der Praxis
So angenehm YAML zu lesen ist, so tückisch kann es bei der Bearbeitung sein. Die häufigsten Fehler tauchen immer wieder auf:
Einrückung und Tabs. YAML erlaubt ausschließlich Leerzeichen zur Einrückung, niemals Tabs. Ein einziger Tab-Charakter bringt den Parser zum Absturz, und die Fehlermeldung ist oft wenig hilfreich. Konfiguriere deinen Editor so, dass er die Tab-Taste in Leerzeichen umwandelt (meist zwei pro Ebene).
Boolean-Autokonvertierung. YAML interpretiert eine ganze Reihe von Wörtern als Wahrheitswert: yes, no, on, off, true, false. Wenn du den norwegischen Ländercode NO als reinen Text meinst oder ein Feld tatsächlich das Wort on enthalten soll, wird daraus ungewollt ein Boolean. Die Lösung sind Anführungszeichen: "no" bleibt Text.
Fehlende Quotes bei Versionsnummern. Werte wie 1.20 oder 3.10 sehen aus wie Zahlen und werden auch als solche gelesen. Aus 3.10 wird dann 3.1, weil die Null hinter dem Komma verschwindet. Bei Versionsangaben, Ports und ähnlichen Kennungen setzt du deshalb immer Anführungszeichen: "3.10". Diese und weitere Stolpersteine beim Umwandeln behandeln wir ausführlich im Ratgeber zu den Fallstricken der JSON-YAML-Konvertierung.
Verwechslung von Datentypen. Ein Wert ohne Anführungszeichen wird vom Parser geraten. Postleitzahlen mit führender Null, Telefonnummern oder Zeitstempel landen so schnell in einem falschen Typ. Wenn du sicher gehen willst, dass etwas Text bleibt, hilft nur das Zitieren.
Tipps zur Pflege
Damit deine YAML-Dateien langfristig sauber bleiben, lohnen sich zwei Werkzeuge im Alltag. Erstens ein Linter wie yamllint. Er prüft nicht nur die Syntax, sondern warnt auch vor stilistischen Problemen wie inkonsistenter Einrückung, zu langen Zeilen oder verdächtigen Boolean-Werten. Du kannst ihn lokal ausführen oder direkt in deine CI-Pipeline einbauen, sodass fehlerhafte Dateien gar nicht erst gemergt werden.
Zweitens die Schema-Validierung. Für viele Formate (Kubernetes-Manifeste, GitHub-Actions-Workflows, Docker Compose) gibt es JSON-Schemas, gegen die du deine YAML-Dateien prüfen kannst. Moderne Editoren binden diese Schemas automatisch ein und zeigen dir schon beim Tippen an, wenn ein Feld falsch geschrieben ist oder ein Wert nicht in den erlaubten Bereich fällt. Das fängt Tippfehler ab, bevor sie im Cluster landen.
Ein praktischer Tipp aus dem Arbeitsalltag: Oft bekommst du eine Konfiguration als JSON, etwa eine API-Antwort oder ein Beispiel aus einer Dokumentation, willst sie aber im lesbareren YAML-Format in deine Config-Datei übernehmen. Statt die Datei von Hand umzuschreiben, kannst du sie auf jsonyaml.de direkt im Browser umwandeln. Die Konvertierung läuft komplett lokal, es wird nichts hochgeladen, und du kopierst das Ergebnis anschließend in dein Repository. Ob YAML in deinem Fall überhaupt die richtige Wahl gegenüber JSON ist, klärt der Ratgeber Wann YAML statt JSON.
YAML ist in DevOps also weniger ein Selbstzweck als ein Werkzeug, das Konfiguration lesbar, kommentierbar und versionierbar macht. Wer die typischen Fallen bei Einrückung, Tabs und Datentypen kennt und mit Linter plus Schema-Validierung arbeitet, hat den Großteil der Probleme im Griff.
Hast du einen Fehler entdeckt oder einen Quellen-Hinweis für uns? Schreib gern an info@akara-solutions.de.
Quellen
- Kubernetes Documentation: Objects and Manifests (kubernetes.io)
- Docker Compose file reference (docs.docker.com)
- GitHub Actions: Workflow syntax (docs.github.com)
Korrekturen oder bessere Quellen? Schreib an info@akara-solutions.de. Änderungen landen mit Datum auf /korrekturen.
