Linux System Administration

Automatisierung: Zielzustand und kontrollierter Rollout

Automatisierung spart Zeit — und beschleunigt im selben Zug den Fehler: Ein falscher Handgriff von Hand trifft einen Host, derselbe Fehler im Playbook trifft alle zweihundert. Dieses Modul zeigt dir die Vorkehrungen, die dazugehören: warum ein Zielzustand etwas anderes ist als eine Befehlsfolge, warum changed=0 beim zweiten Lauf die aussagekräftigste Zahl im Ergebnis ist, welche drei dokumentierten Lücken ein Probelauf hat — sie lassen ihn allesamt sauberer aussehen als die Wirklichkeit —, und wie ein Rollout in Wellen einen Fehler auf einen einzigen Host begrenzt.

Lehrtext · 12 Abschnitte · zuletzt geprüft: 2026-09-03

Was sich ändert, wenn ein Werkzeug die Handgriffe übernimmt

Der übliche Grund für Automatisierung ist Zeitersparnis: Was auf einem Host zwei Minuten dauert, dauert auf zweihundert Hosts zwei Minuten statt sieben Stunden. Das stimmt und ist der weniger wichtige Teil.

Der wichtigere Teil ist, dass die Hosts danach gleich sind. Zweihundert von Hand eingerichtete Server unterscheiden sich immer — in der Reihenfolge der Schritte, in einem übersehenen Handgriff, in einer Anpassung, die jemand vor einem Jahr für einen Sonderfall gemacht und nicht aufgeschrieben hat. Genau diese Unterschiede erzeugen die Fehler, die sich auf einem Host nicht nachstellen lassen.

Ein dritter Effekt wird selten genannt und ist auf Dauer der wertvollste: Das Playbook ist die einzige Beschreibung des Systems, die nicht veralten kann, ohne dass es auffällt. Ein Wiki-Eintrag darf jahrelang falsch sein; ein Playbook, das nicht mehr zur Wirklichkeit passt, schlägt beim nächsten Lauf fehl.

Mit derselben Bewegung skaliert allerdings auch der Fehler. Ein falscher Handgriff von Hand betrifft einen Host; derselbe Fehler im Playbook betrifft alle. Deshalb geht es in diesem Modul nicht darum, wie man etwas automatisiert, sondern darum, welche Vorkehrungen dazugehören: ein Zielzustand statt einer Befehlsfolge, ein Probelauf und seine Lücken, ein Rollout in Wellen und ein Nachweis, der die nächste Welle freigibt.

Zielzustand statt Befehlsfolge

Ein Skript beschreibt Schritte: Paket installieren, Datei kopieren, Dienst starten. Ein Konfigurationswerkzeug beschreibt stattdessen einen Zustand: Dieses Paket soll vorhanden sein, diese Datei soll diesen Inhalt haben, dieser Dienst soll laufen. Wie es dahin kommt — und ob überhaupt etwas zu tun ist —, entscheidet das Werkzeug.

Der Unterschied wird am zweiten Lauf sichtbar. Ein Skript führt seine Schritte erneut aus. Ein Zielzustand wird geprüft und dabei festgestellt, dass er bereits erreicht ist. Deshalb meldet jeder Schritt eines dieser Ergebnisse:

ok
Der Zielzustand war bereits erreicht — nichts wurde angefasst.
changed
Der Ist-Zustand wich ab und wurde angeglichen.
failed
Der Zielzustand konnte nicht hergestellt werden.
skipped
Der Schritt war für diesen Host nicht zutreffend.

IdempotentEin Schritt ist idempotent, wenn seine mehrfache Ausführung dasselbe Ergebnis hat wie eine einmalige. Nicht „er läuft fehlerfrei durch“, sondern: Beim zweiten Mal ändert er nichts mehr.

`changed` ist die aussagekräftigste Zahl im Ergebnis

Aus der Unterscheidung zwischen ok und changed folgt eine Prüfung, die nichts kostet und viel zeigt: Laufe dasselbe Playbook zweimal hintereinander. Meldet der zweite Lauf changed=0, sind alle Schritte tatsächlich idempotent. Meldet er weiterhin Änderungen, ist mindestens einer davon nur scheinbar deklarativ — er schreibt bei jedem Lauf, egal ob nötig oder nicht.

Diese Zahl trägt eine zweite Bedeutung. Läuft ein Playbook regelmäßig über eine Flotte und meldet auf einem Host plötzlich Änderungen, hat dort jemand von Hand eingegriffen. Der Zählwert ist damit gleichzeitig eine Abweichungserkennung — man muss ihn nur beobachten.

Häufige Ursache für ein rauschendes `changed`Eine Vorlage, die einen Zeitstempel oder eine zufällige Kennung enthält, erzeugt bei jedem Lauf eine andere Datei und damit immer changed — mitsamt allen daran hängenden Neustarts. Wer sein Ergebnis als Abweichungssignal nutzen will, muss solche Stellen ausnehmen.

Wo die Idempotenz endet

Nicht für jede Aufgabe gibt es einen fertigen Baustein. Dann greift man zum allgemeinen Befehlsaufruf — und verlässt damit die deklarative Welt. Das Werkzeug kann bei einem beliebigen Befehl nicht wissen, was er bewirkt, ob er nötig ist oder ob er bereits gelaufen ist. Es meldet deshalb bei jedem Lauf changed.

Die Dokumentation des Bausteins sagt das unmissverständlich: Der Befehl selbst sei beliebig und könne der Probelauf-Semantik nicht unterworfen werden; als Behelf gebe es die Angaben creates und removes. Sie beschreiben eine Datei, deren Vorhandensein den Lauf überflüssig macht — damit wird der Aufruf von außen bedingt und der zweite Lauf still.

Ein Befehlsaufruf, der beim zweiten Mal schweigt

Szenario

Ein Playbook richtet ein Datenbankschema ein. Dafür gibt es keinen passenden Baustein, also wird ein Skript aufgerufen.

Anforderungen

  • Das Skript ist nicht wiederholbar — ein zweiter Lauf legt Tabellen doppelt an
  • Es hinterlässt bei Erfolg eine Markierungsdatei

Schritte

  1. Ohne weitere Angabe meldet der Aufruf bei jedem Lauf changed und richtet beim zweiten Mal Schaden an.
  2. Mit creates: /var/lib/app/.schema-ok prüft das Werkzeug zuerst, ob diese Datei existiert.
  3. Existiert sie, wird der Befehl übersprungen und als ok gemeldet.
  4. Der Zielzustand ist damit nicht mehr „das Skript ist gelaufen“, sondern „die Markierung existiert“ — und das ist prüfbar.

Merksatz: Wo ein Baustein die Bedingung nicht selbst kennt, muss man sie ihm geben. Das ist die eigentliche Arbeit an einem solchen Aufruf — nicht der Befehl, sondern die Frage, woran man erkennt, dass er schon gelaufen ist.

Für Aufrufe, die keinen prüfbaren Nebeneffekt hinterlassen — eine Statusabfrage etwa —, gibt es die umgekehrte Möglichkeit: Man legt über changed_when fest, wann der Schritt überhaupt als Änderung gilt. Ein reiner Leseaufruf sollte nie changed melden, sonst löst er Neustarts aus, die niemand beabsichtigt hat.

Der Probelauf und seine dokumentierten Lücken

Vor einer Änderung an einer Flotte will man wissen, was passieren würde. Dafür gibt es den Probelauf: Er führt das Playbook aus, ohne die Zielsysteme zu verändern, und meldet, was er getan hätte. Das ist außerordentlich nützlich — und es hat drei Lücken, die man kennen muss, weil sie alle in dieselbe Richtung wirken.

Nicht unterstützte Bausteine
Die Dokumentation sagt es wörtlich: Bausteine, die den Probelauf nicht unterstützen, melden nichts und tun nichts. Sie erscheinen unauffällig — nicht, weil sie nichts ändern würden, sondern weil sie nicht befragt wurden.
Abhängige Schritte
Ein Schritt, dessen Bedingung auf dem Ergebnis eines vorherigen beruht, kann nicht simuliert werden — das Ergebnis gibt es im Probelauf nicht.
Ausdrückliche Ausnahmen
Ein Schritt mit check_mode: false läuft laut Dokumentation auch im Probelauf echt und verändert das System. Ein Probelauf ist also nicht per se folgenlos.

Alle drei Lücken erzeugen dasselbe Muster: Der Probelauf sieht sauberer aus als die Wirklichkeit. Er beweist deshalb nicht, dass eine Änderung harmlos ist — er beweist nur, dass die simulierbaren Teile harmlos aussehen. Der Rest muss auf echten Hosts geprüft werden, und genau dafür gibt es den Rollout in Wellen.

Ergänzend zeigt der Vergleichsmodus die Datei vorher und nachher — sehr hilfreich bei Vorlagen. Er hat eine eigene Kante: Die Dokumentation weist darauf hin, dass er vertrauliche Inhalte offenlegen kann, und bietet dafür an, ihn für einzelne Schritte über diff: false abzuschalten.

Ein Neustart statt zehn

Ein Dienst soll neu geladen werden, wenn sich seine Konfiguration geändert hat — und nur dann. Dafür gibt es Handler: Schritte, die laut Dokumentation ausschließlich laufen, wenn sie benachrichtigt wurden. Benachrichtigt wird ein Handler, wenn der auslösende Schritt changed meldet.

Drei Eigenschaften machen sie zum richtigen Werkzeug, und alle drei sind ausdrücklich dokumentiert:

  • Ein mehrfach benachrichtigter Handler läuft einmal — auch wenn zehn Schritte dieselbe Konfiguration angefasst haben
  • Handler laufen erst nach allen Schritten des Abschnitts, nicht sofort an Ort und Stelle
  • Ihre Reihenfolge folgt der Definition im Handler-Abschnitt, nicht der Reihenfolge der Benachrichtigungen

Die dritte Eigenschaft ist die, die überrascht. Wer zwei Handler in der gewünschten Reihenfolge benachrichtigt, bekommt trotzdem die Reihenfolge, in der sie weiter unten definiert sind. Wo eine Abfolge zwingend ist — erst die Datenbank, dann die Anwendung —, muss sie also in der Definition stehen.

Wenn früher gebrauchtManchmal muss der Neustart mitten im Ablauf passieren, weil die folgenden Schritte den neu geladenen Dienst brauchen. Dafür gibt es einen ausdrücklichen Schritt, der alle bis dahin aufgelaufenen Handler sofort ausführt. Danach können dieselben Handler laut Dokumentation erneut benachrichtigt werden und später noch einmal laufen.

Rollout in Wellen

In der Voreinstellung wird jeder Schritt auf allen betroffenen Hosts ausgeführt, bevor der nächste beginnt. Für eine Änderung an einer laufenden Flotte ist das die gefährlichste aller Reihenfolgen: Ein Schritt, der Dienste beendet, beendet sie überall gleichzeitig.

Die Gegenmaßnahme ist eine Stapelgröße. Damit wird das gesamte Playbook auf einem Teil der Hosts fertig ausgeführt, bevor der nächste Teil beginnt. Bei sechs Hosts und der Größe drei laufen also erst drei Hosts vollständig durch, dann die anderen drei.

Stapelgröße
Zahl, Prozentsatz oder eine Liste — etwa erst ein Host, dann zehn Prozent, dann der Rest.
Fehlergrenze je Stapel
Bricht den Lauf ab, sobald mehr als ein festgelegter Anteil der Hosts fehlgeschlagen ist. Sie gilt laut Dokumentation je Stapel, nicht über die gesamte Flotte.
Abbruch beim ersten Fehler
Beendet den fehlgeschlagenen Schritt noch auf allen Hosts des aktuellen Stapels und stoppt danach das gesamte Playbook.

Die Liste als Stapelgröße ist das Muster, das man sich merken sollte: eins, dann wenige, dann viele. Der erste Host ist der Kanarienvogel — geht dort etwas schief, betrifft es genau einen. Die zweite Welle prüft, ob das Ergebnis reproduzierbar ist. Erst danach läuft der Rest.

Zur Welle gehört meist mehr als die Änderung selbst. Ein Host, an dem gearbeitet wird, sollte keinen Nutzerverkehr bekommen. Deshalb rahmen zwei weitere Schritte den eigentlichen Eingriff ein: den Host aus der Verteilung nehmen, ändern und prüfen, wieder aufnehmen. Beide Schritte laufen nicht auf dem Zielhost, sondern auf dem Lastverteiler — sie werden also an ein anderes System abgegeben, während die Schleife weiterhin über die Zielhosts läuft.

Reihenfolge, die man leicht falsch herum bautDie Wiederaufnahme in die Verteilung gehört hinter die Wirkungsprüfung, nicht davor. Wer zuerst wieder aufnimmt und dann prüft, schickt im Fehlerfall bereits Nutzerverkehr auf einen kaputten Host — und die Prüfung meldet dann etwas, das die Nutzenden schon gemerkt haben.

Was die erste Welle beweisen muss

Ein Rollout in Wellen nützt nur, wenn zwischen den Wellen etwas geprüft wird. „Das Playbook lief ohne Fehler durch“ ist dafür zu wenig: Es sagt, dass die Schritte ausgeführt wurden, nicht dass der Dienst danach seine Aufgabe erfüllt.

Die Prüfung gehört deshalb in das Playbook selbst — als Schritt am Ende, der eine Aussage über die Wirkung trifft: Der Dienst antwortet auf seiner Schnittstelle, die erwartete Version steht in der Antwort, ein fachlicher Aufruf liefert das richtige Ergebnis. Schlägt diese Prüfung fehl, gilt der Host als fehlgeschlagen, und die Fehlergrenze stoppt den Lauf, bevor die nächste Welle beginnt.

Kurzcheck

Ein Playbook läuft mit den Stapelgrößen 1, 10 und dem Rest über 200 Hosts, mit einer Fehlergrenze von 30 Prozent je Stapel. Im ersten Stapel schlägt der eine Host fehl. Was passiert?

  • Der Lauf bricht ab — 100 Prozent des ersten Stapels sind fehlgeschlagen
  • Der Lauf geht weiter, weil ein Host von 200 deutlich unter der Grenze von 30 Prozent liegt
  • Der Lauf überspringt den fehlgeschlagenen Host und setzt mit dem zweiten Stapel fort

Treffer. Richtig. Die Grenze gilt je Stapel, und der erste besteht aus genau einem Host. Genau deshalb ist die Eins am Anfang der Liste so wirksam: Jede Fehlergrenze wirkt dort als sofortiger Stopp.

Geheimnisse gehören nicht in die Versionsverwaltung

Automatisierung braucht Zugangsdaten: für Datenbanken, Zertifikate, Programmierschnittstellen. Sie landen im selben Repository wie das Playbook, wenn niemand vorher entscheidet, wohin sie sonst gehören — und dann sind sie für jeden lesbar, der das Repository lesen darf, mitsamt der gesamten Historie.

  • Verschlüsselte Ablage im Repository: einfach einzurichten, und das Entschlüsselungsgeheimnis muss dennoch irgendwo liegen
  • Externe Geheimnisverwaltung: Werte werden zur Laufzeit geholt, mit eigener Berechtigung und eigenem Zugriffsnachweis
  • Ausgabeunterdrückung für die betroffenen Schritte, damit Werte nicht im Protokoll erscheinen
  • Vergleichsmodus für Dateien mit vertraulichem Inhalt abschalten

Die dritte Zeile wird am häufigsten vergessen und ist am billigsten zu haben. Ein Schritt, der einen Wert setzt, gibt ihn im Fehlerfall gern vollständig aus — und das Ergebnisprotokoll eines Rollouts landet in einer Pipeline, die deutlich mehr Menschen lesen dürfen als die Geheimnisverwaltung.

Die Grenze aller drei WegeWer das Playbook ausführen darf, kann an die Werte kommen — sonst könnte es sie nicht einsetzen. Verschlüsselung schützt vor dem Mitlesen im Repository, nicht vor dem Ausführenden. Die eigentliche Grenze ist deshalb, wer Läufe auslösen darf, und das ist eine Frage der Berechtigung, nicht der Verschlüsselung.

Die Automatisierung ist selbst ein privilegierter Zugang

Das System, von dem aus die Läufe starten, erreicht jeden Host der Flotte, meist mit weitreichenden Rechten. Damit ist es das lohnendste Ziel im gesamten Bestand: Wer es kontrolliert, kontrolliert alles, was es verwaltet — und zwar über einen Weg, der im Betrieb völlig unauffällig aussieht.

Daraus folgt, dass dieses System dieselbe Behandlung braucht wie ein Verzeichnisdienst oder eine Zertifikatsstelle: eng begrenzter Zugang, nachvollziehbare Auslösung, getrennte Zugangsdaten je Umgebung. Ein Playbook, das ohne Freigabe von einem Arbeitsplatz aus auf die Produktion laufen kann, ist ein administrativer Vollzugriff ohne Kontrolle.

Warum Automatisierung ohne regelmäßigen Lauf verfällt

Ein Playbook, das einmal im Halbjahr läuft, beschreibt nach kurzer Zeit nicht mehr die Wirklichkeit. In der Zwischenzeit hat jemand von Hand eingegriffen, ein Paket hat sein Standardverhalten geändert, ein Pfad ist umgezogen. Der nächste Lauf trifft dann auf eine Umgebung, für die er nie geschrieben wurde.

Das erzeugt eine unangenehme Rückkopplung: Weil der Lauf riskant ist, wird er weiter aufgeschoben, und mit jedem Aufschub wächst der Abstand. Ein Playbook, das täglich läuft, ändert dagegen bei jedem Lauf wenig — und was es ändert, gehört zu genau einer Ursache.

Die praktische Empfehlung ist deshalb, den Lauf regelmäßig zu machen, auch wenn keine Änderung ansteht. Ob er dabei tatsächlich eingreifen darf oder zunächst nur meldet, ist eine getrennte Entscheidung — der Wert liegt schon darin, die Abweichung zu sehen, solange sie klein ist.

Der Ablauf einer Flottenänderung

Zielzustand formulieren, nicht Befehlsfolge — und zweimal laufen lassen, bis changed=0 stehtProbelauf mit Vergleichsmodus, im Wissen um seine drei LückenWirkungsprüfung als letzten Schritt ins Playbook aufnehmenStapelgrößen eins, wenige, viele — mit Fehlergrenze je StapelErste Welle auswerten, bevor die zweite startetRegelmäßig wiederholen, damit die Abweichung klein bleibt

Der vierte Punkt ist die Vorkehrung, die einen Fehler auf einen Host begrenzt. Der dritte ist die, die ihn überhaupt bemerkt. Ohne den dritten läuft der vierte sauber durch — und verteilt die Änderung über alle Wellen, weil kein Schritt fehlgeschlagen ist.

Jetzt anwenden

Diesen Stoff gibt es als Modul mit bewerteten Entscheidungs-Checks — dieselbe Einführung, danach die Übungen.

Zum Modul →
Quellen & Aktualität7 Primärquellen · zuletzt geprüft:
  1. 01docs.ansible.com/ansible/latest/playbook_guide…books_checkmode.html
  2. 02docs.ansible.com/ansible/latest/playbook_guide…ybooks_handlers.html
  3. 03docs.ansible.com/ansible/latest/playbook_guide…ooks_strategies.html
  4. 04docs.ansible.com/ansible/latest/playbook_guide…_error_handling.html
  5. 05docs.ansible.com/ansible/latest/collections/an…/command_module.html
  6. 06docs.ansible.com/ansible/latest/vault_guide/index.html
  7. 07docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html