5. Ausführung#
Das Playbook lief seit Monaten einwandfrei: zehn Access-Switches im Labor, zwei Minuten von Anfang bis Ende, saubere Ergebnisse jedes Mal. Als das Team beschloss, es auf das vollständige Inventar von 800 Switches auszurollen, erwartete niemand Probleme. Die ersten 600 Geräte wurden ohne Zwischenfälle aktualisiert. Dann verlangsamte sich der Job. Dann stockte er. Der RADIUS-Server, der plötzlich 150 gleichzeitige SSH-Authentifizierungsanfragen erhielt, begann, Verbindungen abzulehnen. Ansible hing bei 150 Geräten mitten in der Ausführung. Ein Ingenieur beendete den Job.
Was danach kam, war das schwierigere Problem: Niemand wusste, welche der 600 Geräte aktualisiert worden waren und welche 150 nicht. Es wurde kein Ausführungsstatus aufgezeichnet. Sie führten das Playbook erneut aus und hofften, dass Idempotenz sie retten würde - das tat sie, diesmal. Aber der Vorfall enthüllte etwas Wichtiges: Die Ausführungsschicht war für das Labor konzipiert worden, nicht für das Netzwerk. Geschwindigkeit, Parallelität, Fehlergrenzen, Statusverfolgung - nichts davon war berücksichtigt worden. Die Automatisierung funktionierte; die Ausführungsarchitektur nicht.
Die meisten Menschen denken bei Netzwerkautomatisierung an: “Dieselben Daten nehmen und ohne menschliche Verbindung über die CLI, etwas im Netzwerk tun.” Ich würde wetten, dass die meisten Menschen, die mit Netzwerkautomatisierung beginnen, dort anfangen. Und ja, das ist es, was der Ausführungsblock tut. Aber wie Sie im Laufe dieses Buches gesehen haben, ist Netzwerkautomatisierung mehr als dieser erste Schritt, und die Ausführung ist nur eine Komponente innerhalb einer Architektur.
Der Ausführungsblock interagiert direkt mit dem Netzwerk für die gefährlichsten Operationen (z.B. Konfigurationsänderungen oder Neustarts). Überspringen Sie dieses Kapitel also nicht; es ist entscheidend, es richtig zu machen.
In diesem Kapitel behandeln wir die Ziele und Säulen, die dieser Block bietet, sowie die internen Fähigkeiten, die er zur Erreichung dieser Ziele benötigt.
5.1. Grundlagen#
5.1.1. Kontext#
Die Ausführung definiert wie Aktionen ausgeführt werden. Das Was kommt vom Intent-Block und das Wann von der Orchestrierung.
Bei frühen Netzwerkautomatisierungsprojekten kann ein Skript, das eine Schnittstelle für ein bestimmtes Gerät und einen bestimmten Schnittstellennamen zurücksetzt, der erste Erfolg sein. Diese Reise kann sich zu einem viel ausgefeilteren System entwickeln.
5.1.2. Ziele#
Was muss ein Ausführungssystem tatsächlich tun? Fünf Dinge sind wichtig:
Die richtigen Daten an die richtige Stelle bringen. Vor der Ausführung von irgendetwas muss man wissen, was ausgeführt werden soll (die Absicht), wo es ausgeführt werden soll (welche Geräte) und wie man darauf zugreift (Zugangsdaten, Verbindungsdetails). Das bedeutet, Inventar abzurufen und den beabsichtigten Zustand aus dem Source of Truth zu holen (mehr dazu in Kapitel 4) und manchmal Observability-Daten abzufragen, um aktuelle Bedingungen zu verstehen. Ohne diese Integration läuft die Ausführungs-Engine blind Befehle aus. Zur eigenen Nervenberuhigung sollte man das vermeiden.
Starten wenn nötig, sei es jetzt oder später. Manchmal braucht man sofortige Ausführung: Ein Ingenieur klickt auf “Bereitstellen” und erwartet, dass es sofort geschieht. In anderen Fällen sollte die Ausführung warten, während des Wartungsfensters bereitstellen, warten bis ein Gerät online kommt oder auf ein Ereignis aus der Observability reagieren. Das System muss sowohl synchrone als auch asynchrone Auslöser unterstützen.
Status über die Zeit verfolgen. Netzwerkweite Operationen sind nicht augenblicklich. Man könnte Hunderte von Geräten über Stunden hinweg bereitstellen. Welche Geräte waren erfolgreich? Welche scheiterten? Welche stehen noch aus? Status-Management ermöglicht auch Idempotenz (dieselbe Aufgabe zweimal ausführen, dasselbe Ergebnis erhalten), Rollback (rückgängig machen, was gerade getan wurde) und Wiederaufnahme (nach einem Fehler dort weitermachen, wo man aufgehört hat). Ohne Statusverfolgung ist jede Ausführung ein Einmal-Glücksspiel.
Zuverlässig und in großem Maßstab ausführen. Ein Skript, das für 5 Geräte funktioniert, bricht oft bei 500 zusammen (oder verschlechtert sich). Man braucht parallele Ausführung, Fehlerbehandlung, Wiederholungsversuche, Rate-Limiting und Dry-Run-Fähigkeiten. Das System sollte teilweise Ausfälle elegant handhaben, klares Feedback geben, was schieflief, und das Netzwerk niemals in einem undefinierten Zustand hinterlassen. Verschiedene Operationen benötigen verschiedene Strategien. Manche sind schnell und parallel, andere langsam und seriell.
Mit jedem Netzwerkgerät oder jeder Plattform arbeiten. Das Netzwerk hat wahrscheinlich Cisco, Arista, Juniper, Cloud-Application Programming Interface (API)s, Linux-Rechner, Firewalls und Load-Balancer. Jedes spricht verschiedene Protokolle und hat verschiedene Betriebsmuster. Die Ausführungsschicht benötigt Adapter für alle davon, mit einer gemeinsamen Schnittstelle, sodass der Rest der Automatisierung sich nicht um die Unterschiede kümmern muss.
Mit diesen Zielen vor Augen: Welche Architektur-Fähigkeiten braucht man tatsächlich?
5.1.3. Säulen#
Jedes Ziel übersetzt sich in spezifische Fähigkeiten:
Datenintegrations-Schicht. Die Ausführungs-Engine existiert nicht im Vakuum. Sie benötigt programmatischen Zugriff auf den Source of Truth (Inventar, Zugangsdaten, Absicht), auf Observability-Systeme (aktueller Zustand, Gesundheitsmetriken) und möglicherweise auf andere Systeme (Ticketing, Change-Management, Genehmigungsworkflows). Das bedeutet die Implementierung von Application Programming Interface (API)-Clients, sicheres Handling der Authentifizierung, angemessenes Caching von Daten und die Validierung, dass alles Nötige vorhanden ist, bevor die Ausführung beginnt.
Flexible Auslösemechanismen. Mehrere Möglichkeiten, die Ausführung zu starten, sind wichtig. Synchrone Auslöser umfassen Representational State Transfer (REST)-Application Programming Interface (API)-Aufrufe (direkte Aufrufung), Webhooks (externe Systemintegration) und Remote-Procedure-Calls. Asynchrone Auslöser umfassen Event-Listener (reagieren auf Observability-Alarme, Gerätezustandsänderungen oder externe Ereignisse), Planer (cron-ähnliche periodische Ausführung oder einmalig geplante Aufgaben) und Message-Queue-Konsumenten. Einfaches Verketten hilft ebenfalls: Eine Ausführung ist abgeschlossen und löst eine weitere aus.
Status-Management-Infrastruktur. Das geht über “hat das Gerät diese Konfiguration” hinaus. Man braucht Ausführungsstatus (welche Aufgaben laufen, stehen aus, sind abgeschlossen, sind gescheitert), Soll-Zustand (was konfiguriert sein sollte) und Ist-Zustand (was konfiguriert ist). Das erfordert persistenten Speicher, Transaktionsunterstützung für atomare Operationen, Sperrmechanismen zur Verhinderung gleichzeitiger Konflikte und ein klares Statusmodell. Die Infrastruktur muss verteilte Szenarien handhaben, bei denen der Status über mehrere Ausführungs-Worker hinweg geteilt wird.
Robuste Ausführungs-Engine. Das ist das Herzstück des Systems. Sie unterstützt sowohl imperative Workflows (Befehl 1 ausführen, dann Befehl 2, dann Befehl 3) als auch deklarative Ansätze (das Gerät soll so aussehen, die Schritte selbst herausfinden). Die Engine handhabt Parallelität (gleichzeitig gegen mehrere Geräte oder in Batches ausführen), implementiert Wiederholungslogik mit exponentiellen Wartezeiten, bietet Dry-Run-Fähigkeiten (voraussagen, was passieren würde, ohne es tatsächlich zu tun), erfasst detaillierte Ausführungsprotokolle und handhabt teilweise Ausfälle elegant. Fehlerbehandlung ist kritisch: Wenn etwas scheitert, soll alles abgebrochen, mit anderen Geräten fortgefahren oder ein Neuversuch unternommen werden?
Protokollabstraktions-Schicht. Netzwerkgeräte sind ein heterogenes Durcheinander. Manche sprechen Secure Shell (SSH) und erwarten Command Line Interface (CLI)-Befehle. Andere nutzen NETCONF oder RESTCONF. Moderne Geräte unterstützen gRPC Network Management Interface (gNMI) für Streaming-Telemetrie und Konfiguration. Cloud-Plattformen stellen Representational State Transfer (REST)-APIs bereit. Das Ausführungssystem benötigt Adapter für all diese, die eine einheitliche Schnittstelle für die übergeordnete Logik präsentieren. Diese Schicht handhabt Connection-Pooling, Session-Management, Authentifizierung, Befehlsformatierung und Response-Parsing. Gute Abstraktion bedeutet, dass man Unterstützung für einen neuen Gerätetyp hinzufügen kann, ohne die gesamte Automatisierung neu zu schreiben.
5.1.4. Geltungsbereich#
Der Ausführungsblock sitzt zwischen Planung und Aktion. Er erhält Anweisungen von Intent (was konfiguriert werden soll) und Orchestrierung (wann und wie), dann interagiert er direkt mit Netzwerkgeräten, um Änderungen umzusetzen.
Im Geltungsbereich:
- Verbindung zu Netzwerkgeräten über ein beliebiges unterstütztes Protokoll
- Ausführung von Konfigurationsänderungen, operativen Befehlen, Dateiübertragungen, Neustarts
- Verwaltung des Ausführungsstatus und Verfolgung des Fortschritts
- Behandlung von Fehlern, Wiederholungsversuchen und Rollbacks
- Feedback an die Orchestrierung
Außerhalb des Geltungsbereichs:
- Entscheiden, was konfiguriert werden soll (das ist Intent)
- Orchestrierung komplexer mehrstufiger Workflows und Entscheiden, wann ausgelöst werden soll (das ist Orchestrierung)
- Langzeitspeicherung und Analyse von Ausführungsergebnissen (das ist Observability)
Denken Sie an die Ausführung als Motor eines Autos: Sie liefert Kraft und Bewegung, entscheidet aber nicht, wohin man fährt oder wann man abbiegt. Diese Entscheidungen kommen vom Fahrer (Orchestrierung), der einer Karte (Intent) folgt.
5.2. Funktionalitäten#
Fünf Schlüsselfunktionsbereiche arbeiten zusammen, um den Netzwerkzustand sicher und zuverlässig zu ändern:
- Datenintegration: Abruf von Inventar, Zugangsdaten, Absicht und Observability-Daten aus vorgelagerten Systemen
- Auslösung: Initiierung der Ausführung durch synchrone oder asynchrone Mechanismen
- Status-Management: Verfolgung des Ausführungsfortschritts, Ermöglichung von Idempotenz und Rollback
- Engine: Die Kernlogik, die Aufgaben mit angemessener Parallelität und Fehlerbehandlung ausführt
- Netzwerkadapter: Protokollspezifische Schnittstellen zur Kommunikation mit verschiedenen Netzwerkgeräten
Diese Komponenten bilden eine Pipeline: Datenintegration liefert die Eingaben, Auslösung startet den Prozess, die Engine führt Aufgaben über Netzwerkadapter aus, und das Status-Management verfolgt alles.
graph LR
subgraph Goals
G1[Die richtigen Daten an die richtige Stelle]
G2[Starten wenn nötig]
G3[Status über die Zeit verfolgen]
G4[Zuverlässig und in großem Maßstab ausführen]
G5[Mit jedem Netzwerkgerät oder jeder Plattform arbeiten]
end
subgraph Pillars
P1[Datenintegrations-Schicht]
P2[Flexible Auslösemechanismen]
P3[Status-Management-Infrastruktur]
P4[Robuste Ausführungs-Engine]
P5[Protokollabstraktions-Schicht]
end
subgraph Functionalities
F1[Datenintegration]
F2[Auslösung]
F3[Status-Management]
F4[Engine]
F5[Netzwerkadapter]
end
G1 --> P1 --> F1
G2 --> P2 --> F2
G3 --> P3 --> F3
G4 --> P4 --> F4
G5 --> P5 --> F5
Die interne Architektur sieht so aus:
graph TD
A[Datenintegration] --> C[Engine]
B[Auslösung] --> C[Engine]
C --> E[Status-Management]
E --> C
C --> D[Netzwerkadapter]
classDef component fill:#e1f5ff,stroke:#4a90e2,stroke-width:2px;
class A,B,C,D,E component;
5.2.1. Datenintegration#
Vor der Ausführung von irgendetwas braucht man Daten. Die Ausführungs-Engine bezieht Informationen aus mehreren Quellen, um zu verstehen, was zu tun ist und wo es zu tun ist.
5.2.1.1. Inventar#
Inventardaten definieren die Zielgeräte. Das wurde in Kapitel 4 behandelt, aber das Minimum ist:
- Ziel: IP-Adresse oder FQDN zur Erreichung des Geräts
- Plattform/OS: Gerätetyp, Anbieter, OS-Version (bestimmt, welches Protokoll und welche Befehle verwendet werden)
- Zugangsdaten: Benutzername/Passwort, Secure Shell (SSH)-Schlüssel, Application Programming Interface (API)-Tokens, Zertifikatpfade
- Verbindungsparameter: Secure Shell (SSH)-Port, Timeout-Werte, Application Programming Interface (API)-Endpunkte
- Metadaten: Standortlage, Rolle (Spine/Leaf/Edge), Umgebung (Produktion/Staging)
Inventardaten sollten aus dem Source of Truth kommen. Die Verwendung von Dateien funktioniert nur in sehr kleinen Umgebungen gut. Die Ausführungs-Engine fragt zur Laufzeit die Source-of-Truth-Application Programming Interface (API) ab (oder empfängt die Daten über die Orchestrierung beim Auslösen). Manche Systeme cachen das Inventar für Leistungszwecke mit konfigurierbaren Aktualisierungsintervallen oder nutzen ereignisgesteuertes Inventar, das den Auslöser mit den zugehörigen Informationen kombiniert.
Zugangsdaten niemals in Inventardateien oder Protokollen speichern. Ein Secrets-Management-System verwenden (HashiCorp Vault, AWS Secrets Manager, CyberArk) und Zugangsdaten zur Ausführungszeit injizieren. Der Source of Truth sollte Verweise auf diese sensiblen Daten bereitstellen und sie zur Laufzeit abrufen. Die Ausführungs-Engine sollte mehrere Zugangsdatenquellen und gerätespezifische Zugangsdaten-Overrides unterstützen.
5.2.1.2. Beabsichtigte Daten#
Beabsichtigte Daten sind das, was man konfigurieren oder ändern möchte. Das kommt vom Intent/Source-of-Truth-Block und kann Folgendes umfassen:
- Konfigurationsartefakte: Sofort einsatzbereite Artefakte, die strukturierte Daten sein können, die direkt mit APIs verwendet werden, oder eine Reihe von CLI-Befehlen, die die Konfiguration aufbauen.
- Befehle: Spezifische Command Line Interface (CLI)-Befehle oder Application Programming Interface (API)-Aufrufe zur Ausführung von Geräteoperationen.
- Dateien: Software-Images für Upgrades, Konfigurationsdateien zum Import.
Soll die Ausführungs-Engine Intent-Daten selbst holen oder sollte die Orchestrierung sie übergeben? Beides funktioniert. Das direkte Abrufen von Absichten koppelt die Ausführung an den Source of Truth, stellt aber sicher, dass Daten immer frisch sind. Den Intent als Parameter zu empfangen macht die Ausführung generischer, erfordert aber, dass die Orchestrierung den Datenabruf handhabt.
Meine Empfehlung ist, Konfigurationsartefakte direkt zu konsumieren. Der Intent-Block sollte verantwortlich sein für die Generierung des Konfigurationsartefakts mit eigener Logik, Rendering von Konfigurationsvorlagen mit strukturierten Daten, die den Zustand repräsentieren (VLAN-Konfigurationen, Routing-Richtlinien, ACLs).
Konfigurationsartefakte können zwischen dem Moment ihrer Generierung und dem Moment ihrer Nutzung durch den Executor veralten. Wenn sich die SoT-Daten ändern, nachdem ein vorab generiertes Artefakt gecacht wurde, könnte der Executor eine veraltete Konfiguration anwenden. Das Veralterungsfenster ist die Zeit zwischen dem letzten SoT-Commit und dem Ausführungsauslöser. Für Automatisierungen, die Artefakte zum Auslösezeitpunkt abrufen (statt aus einem Cache), ist dieses Fenster minimal. Für Pipelines, die Artefakte nach einem Zeitplan vorrendern und für die spätere Verwendung speichern, kann das Fenster auf Stunden anwachsen. Wenn Datenfrische wichtig ist, sollte der Orchestrator oder Ausführungsauslöser immer ein frisches Artefakt aus dem SoT beziehen, nicht aus einer gecachten Datei.
5.2.1.3. Beobachtete Daten#
Die Observability-Validierung gehört normalerweise zur Orchestrierung, die entscheiden kann, ob sie fortfahren soll. In einfachen Fällen, in denen die Orchestrierung noch nicht existiert, kann die Ausführung diese Rolle übernehmen.
Hier sind einige Anwendungsfälle, bei denen Observability-Daten nahe am Ausführungsfluss verwendet werden:
- Vorab-Validierung: Ist das Gerät erreichbar? Gibt es genug Speicherplatz für ein Upgrade? Gibt es aktive Sitzungen, die unterbrochen würden?
- Graceful Degradation: Bevor ein Switch neu gestartet wird, Observability abfragen, ob es redundante Konnektivität gibt. Falls nicht, verzögern oder abbrechen.
- Bedingte Logik: Eine Konfiguration nur anwenden, wenn bestimmte Bedingungen erfüllt sind (CPU unter Schwellenwert, keine aktiven Alarme, Tageszeit im Zeitfenster)
- Kapazität entleeren: Vor der Ausführung einer Entleerungsoperation sicherstellen, dass die verfügbare Kapazität ausreicht, um die Änderung ohne SLO-Verletzungen aufzunehmen.
Das erfordert die Integration mit Observability-Systemen. Die Ausführungs-Engine könnte Application Programming Interface (API)s nach aktuellen Metriken abfragen, den Gerätestatus prüfen oder auf Bereitschaftssignale warten. Die Orchestrierung kann diese Integration ebenfalls übernehmen und die Ausführung dann basierend auf Frische und Risiko steuern.
Ein häufiges Muster: Werkzeuge wie die “network health checks”-Module von Ansible oder Nornirs Datenerhebungsaufgaben führen Observability-Abfragen vor und nach der Ausführung durch und vergleichen Ergebnisse, um unerwartete Änderungen zu erkennen. Der “Vorher-/Nachher-Snapshot”-Ansatz erkennt Regressionen, die sonst unbemerkt bleiben würden.
5.2.2. Auslösung#
Die Ausführung startet nicht von selbst. Irgendetwas muss sie auslösen. Moderne Ausführungssysteme unterstützen mehrere Auslösemechanismen:
Synchron (sofortig, blockierend):
- Representational State Transfer (REST)-Application Programming Interface (API)-Aufrufe: Ein externes System oder Benutzer ruft einen Application Programming Interface (API)-Endpunkt auf, die Ausführung läuft und die Antwort enthält Ergebnisse. Einfach und direkt.
- Webhooks: Externe Systeme (Term "git" not found, Ticketing, CI/CD) senden HTTP-Anfragen, wenn Ereignisse eintreten. Häufiges Muster: Term "git" not found-Push löst Konfigurationsbereitstellung aus.
- Command Line Interface (CLI)-Befehle: Ingenieure führen Befehle aus, die die Ausführung direkt aufrufen (
ansible-playbook,terraform apply, benutzerdefinierte Skripte). Diese CLI-Befehle sind Teil der leichtgewichtigen Präsentationsschicht, die diese Werkzeuge bieten (mehr in Kapitel 8).
Asynchron (verzögert oder ereignisgesteuert):
- Event-Listener: Auf Ereignisse aus der Observability reagieren (Gerät ausgefallen, Schwellenwert überschritten), Message-Queues oder externe Systeme. Ansible Event-Driven Automation (EDA) baute dieses Muster explizit auf: Auf Ereignisse hören, Regeln abgleichen, Playbooks automatisch auslösen.
- Message-Queues: Aufgaben in eine Queue einreichen (RabbitMQ, Kafka, AWS SQS), Worker ziehen und führen sie aus. Ermöglicht Pufferung, Prioritätswarteschlangen und Rate-Limiting.
Der richtige Ansatz hängt vom Anwendungsfall ab. Sofortige Änderungen (Behebung eines Produktionsproblems) benötigen synchrone Auslöser. Reaktive Automatisierung (auf Alarme reagieren) verwendet Event-Listener. Auch Skalierungsaspekte spielen eine Rolle, wie wir in Kapitel 11 behandeln.
Die Auslösung kommt normalerweise aus der Orchestrierung, obwohl andere Blöcke die Ausführung direkt auslösen können, wenn keine Orchestrierung vorhanden ist. Zum Beispiel das direkte Auslösen aus der Präsentationsschicht als für Menschen zugängliche Aufgabe oder aus dem Source-of-Truth-Block.
Eine wichtige Überlegung: Was gilt als Ausführung? Für mich ist eine Ausführung mehr als eine einfache Aufgabe. Sie kann mehrere verkettete Aufgaben umfassen, die keinen komplexen Workflow erfordern (das ist die Aufgabe der Orchestrierung). Die Grenze verschwimmt (wieder). Zum Beispiel kann diese Sequenz noch ein einziger Ausführungsfluss sein: Firmware upgraden, auf Geräteneustart warten, Betrieb verifizieren, Inventar aktualisieren. Aber wenn menschliche Validierung oder bedingte Verzweigung basierend auf umfangreicherer Validierung erforderlich ist, gehört das in den Orchestrierungsblock.
5.2.3. Status-Management#
Status-Management bedeutet, zu verfolgen, wo man sich in einer Ausführung befindet und wie die Welt aussieht, um intelligente Entscheidungen zu treffen. Es gibt zwei Hauptkategorien:
Ausführungsstatus (Verfolgung der Automatisierung selbst):
- Welche Geräte wurden verarbeitet?
- Welche Aufgaben haben erfolgreich abgeschlossen, sind gescheitert oder stehen noch aus?
- Wenn eine Aufgabe mit einem vorübergehenden Fehler scheiterte, kann sie wiederholt werden?
- Wenn die Ausführung unterbrochen wurde, kann sie dort wieder aufgenommen werden, wo sie aufgehört hat?
Tatsächlicher Infrastrukturstatus (Verfolgung des Zielkonfigurationsstatus):
- Was ist aktuell konfiguriert?
Zwei Ansätze existieren:
Zustandslos/Agentless (z.B. Ansible). Jede Ausführung läuft unabhängig. Kein persistenter Status zwischen Läufen. Jede Ausführung beginnt neu: Aktuellen Status erheben, Diff berechnen, Änderungen anwenden. Einfacher zu betreiben (keine Status-Datenbank), aber weniger effizient (man entdeckt jedes Mal alles neu) und kein eingebauter Rollback.
Zustandsbehaftet (z.B. Terraform). Das System führt eine persistente Status-Datei, die verfolgt, was zuletzt bereitgestellt wurde. Bei jedem Lauf wird der Soll-Zustand (die eigene Konfiguration) mit dem aufgezeichneten Status (was zuletzt bereitgestellt wurde) und dem Ist-Zustand (was auf dem Gerät ist) verglichen. Dies ermöglicht präzise Änderungsplanung, effiziente Ausführung (nur ändern, was unterschiedlich ist) und Rollback (zum vorherigen Status zurückkehren). Aber jetzt hat man eine Status-Datei zu schützen, zu sperren und über mehrere Betreiber hinweg zu synchronisieren.
Transaktionale Ausführung ist der nächste Schritt, wenn man stärkere Sicherheitsgarantien als “beste Bemühung” möchte. Eine Transaktion fasst mehrere Geräteänderungen in einer Einheit zusammen: Entweder wird alles angewendet und validiert, oder das System rollt zum vorherigen Status zurück. Das erfordert drei Dinge:
- Eine klare Grenze (welche Operationen sind innerhalb der Transaktion)
- Eine dauerhafte Aufzeichnung des Zustands vor der Änderung (für Rollback)
- Einen Sperr- oder Lease-Mechanismus, um zu verhindern, dass gleichzeitige Änderungen die Atomarität brechen
In der Praxis verwendet die meiste Netzwerkautomatisierung “transaktionsähnliches” Verhalten statt strenger ACID-Semantik, weil nicht alle Geräte native Commit/Rollback unterstützen. Dennoch kann man Transaktionen annähern, indem man Snapshots erstellt, Kandidaten-Konfigurationen verwendet (wenn unterstützt), exklusive Sperren durchsetzt und Rollback-Pfade als erstklassigen Teil des Ausführungsflusses behandelt.
Die Herausforderung? Status-Synchronisierung und -Weitergabe. Wenn mehrere Personen oder Systeme Netzwerkgeräte modifizieren, wird der Status veraltet. Terraform begegnet dem mit Remote-Status-Speicherung und Sperrung. Ansible vermeidet das Problem durch Zustandslosigkeit, opfert aber Effizienz. Der Mittelweg: Aktuellen Status vorübergehend cachen, vor jeder Operation validieren und “eventuelle Konsistenz”-Muster aufbauen, bei denen kurze Unstimmigkeiten akzeptabel sind.
5.2.3.1. Idempotenz#
Idempotenz bedeutet, dass die mehrfache Ausführung derselben Automatisierung dasselbe Ergebnis produziert. Eine VLAN-Konfiguration einmal anwenden: VLAN wird erstellt. Erneut anwenden: nichts ändert sich (VLAN existiert bereits). Das ist für Zuverlässigkeit entscheidend: Wenn die Ausführung auf halbem Weg scheitert, kann sie sicher erneut ausgeführt werden, ohne Duplikate zu erstellen oder Dinge zu beschädigen.
Wie Werkzeuge Idempotenz erreichen:
Eingebaute Module (z.B. Ansible): Die meisten Ansible-Module sind von Natur aus idempotent. Das
ios_vlan-Modul prüft, ob das VLAN existiert, bevor es erstellt wird. Wenn es bereits mit korrekter Konfiguration vorhanden ist, meldet Ansible “ok” (keine Änderung). Das erfordert, dass der Modul-Autor Prüflogik implementiert.Statusvergleich (z.B. Terraform): Terraform vergleicht den Soll-Zustand mit dem aktuellen Status, berechnet einen Diff und wendet nur die Unterschiede an. Wenn man
terraform applyzweimal mit unveränderten Konfigurationen ausführt, tut der zweite Lauf nichts.Deklarative APIs (z.B. NETCONF/YANG): Manche Protokolle handhaben Idempotenz nativ. NECONFs
<edit-config>mitmerge-Operation ist inhärent idempotent: Es führt die Konfiguration mit der vorhandenen zusammen und erstellt oder aktualisiert nach Bedarf.Manuelle Prüfung (z.B. Raw-Skripte): Wenn man Python- oder Go-Skripte schreibt, implementiert man Idempotenz selbst: Aktuellen Status abfragen, mit Soll-Zustand vergleichen, Änderungen nur bei einem Diff vornehmen.
Idempotenz ist schwieriger als sie aussieht. Was ist, wenn das VLAN existiert, aber falsche Einstellungen hat? Soll es aktualisiert werden (möglicherweise den Datenverkehr störend) oder soll ein Konflikt gemeldet werden? Was ist mit vorübergehenden Fehlern (Gerät vorübergehend nicht erreichbar)? Wiederholungslogik muss zwischen “Operation bereits erledigt” (idempotenter Erfolg) und “Operation gescheitert” (echter Fehler) unterscheiden.
Perfekte Idempotenz fügt Overhead hinzu. Jede Operation erfordert zunächst eine Abfrage des aktuellen Status. Für groß angelegte Bereitstellungen verlangsamt das die Dinge. Manche Teams akzeptieren “meistens idempotent” (funktioniert 99% der Zeit) statt “perfekt idempotent” (funktioniert immer, aber läuft langsam).
Idempotenz ist eine Anforderung für den deklarativen Ansatz. Jemand muss die Last der Idempotenz tragen und die Komplexität für alle anderen verbergen.
5.2.4. Engine#
Die Ausführungs-Engine ist die Kernlogik, die eine Aufgabe (“dieses VLAN auf diesen 50 Switches konfigurieren”) nimmt und sicher und effizient ausführt. Das ist nicht Orchestrierung. Der Orchestrierungsblock koordiniert mehrere Ausführungsaufgaben über Zeit und Abhängigkeiten. Die Engine führt einfach eine Aufgabe gut aus (oder eine einfache Kette von Aufgaben).
Was sie tut:
- Eine Aufgabendefinition akzeptieren (was zu tun ist, welche Geräte)
- In atomare Operationen aufteilen (Aktionen pro Gerät)
- Operationen mit angemessener Parallelität ausführen (seriell, parallel, gebatcht)
- Fehler, Wiederholungsversuche und Rollbacks handhaben
- Fortschritt und Ergebnisse melden
Eine Ausführungs-Engine könnte 100 Router parallel konfigurieren, entscheidet aber nicht wann sie zu konfigurieren sind, welche Konfigurationen basierend auf Geschäftslogik anzuwenden sind, oder was als nächstes basierend auf Ergebnissen zu tun ist. Das sind Orchestrierungsbelange. Die Ausführung ist das Arbeitstier; die Orchestrierung ist der Vorarbeiter.
Dennoch unterstützen Ausführungs-Engines oft einfaches Verketten: “Aufgabe A ausführen, dann Aufgabe B auf denselben Geräten.” Das ist grundlegende Sequenzierung, keine vollständige Orchestrierung. Wenn man komplexe Workflows braucht (auf externe Genehmigung warten, basierend auf Ergebnissen verzweigen, über mehrere Systeme koordinieren), braucht man eine echte Orchestrierungsschicht (mehr in Kapitel 7).
5.2.4.1. Sprachen#
Wie definiert man die Ausführungslogik? Verschiedene Sprachstile haben verschiedene Abwägungen:
| Stil | Beispiele | Stärken | Abwägungen |
|---|---|---|---|
| Domänenspezifische Sprachen (DSLs) | Ansible (YAML), Terraform (HCL) | Niedrigere Einstiegshürde, selbstdokumentierende Absicht, eingebaute Ausführungssemantik | Begrenzte Flexibilität, schwierigeres Debugging in komplexen Szenarien, bedingte Logik kann umständlich werden |
| Allgemeine Programmiersprachen | Nornir (Python), benutzerdefinierte Python/Go-Skripte | Volle Flexibilität, starke Debugging-Werkzeuge, einfache Bibliothekswiederverwendung | Höhere Kompetenzanforderung, mehr Code zu pflegen, weniger Standardisierung über Teams hinweg |
Viele Teams verwenden DSLs (Ansible) für gängige Muster und wechseln zu benutzerdefiniertem Code (Python-Module, Plugins) für komplexe Sonderfälle. Das balanciert Zugänglichkeit mit Leistungsfähigkeit. Der menschliche Faktor entscheidet normalerweise, welcher Ansatz gewinnt - mehr dazu in Kapitel 13.
5.2.4.2. Imperativ versus Deklarativ#
Imperativ: Man spezifiziert wie etwas getan werden soll, Schritt für Schritt.
Deklarativ: Man spezifiziert, was der Endzustand sein soll, und das Werkzeug findet heraus, wie.
Kurz gesagt: Deklarativ bevorzugen, wenn es passt.
Eine gute Möglichkeit, den Unterschied zu sehen, ist ein Blick auf Ansible, das beides unterstützt:
Imperatives Ansible:
- name: Create VLAN 100 cisco.ios.ios_command: commands: - vlan 100 - name EngineeringMan teilt Ansible buchstäblich mit, welche Befehle auszuführen sind. Wenn das VLAN existiert, läuft dies trotzdem (obwohl es je nach Modul idempotent sein könnte).
Deklaratives Ansible:
- name: Ensure VLAN 100 exists cisco.ios.ios_vlans: config: - vlan_id: 100 name: Engineering state: mergedMan beschreibt den Soll-Zustand. Ansible findet heraus, welche Befehle ausgeführt werden sollen. Wenn VLAN 100 bereits mit korrektem Namen existiert, tut Ansible nichts.
| Ansatz | Stärken | Abwägungen |
|---|---|---|
| Deklarativ | Inhärent idempotent; Absicht ist leichter zu lesen; weniger Operatorfehler, weil das Werkzeug Sonderfälle handhabt | Stark abhängig von Modul-/Anbieterqualität; weniger Kontrolle über den Ausführungspfad; Troubleshooting kann schwieriger sein, wenn Interna abstrahiert sind |
| Imperativ | Volle Kontrolle über jeden Schritt; Ausführungsfluss ist explizit; funktioniert in fast jeder Umgebung mit CLI-Zugang | Mehr Code und Testaufwand; Idempotenz liegt bei einem selbst; langfristige Wartung wächst schnell, wenn Sonderfälle sich häufen |
Die meisten Teams verwenden Deklarativ, wenn möglich, Imperativ, wenn nötig. Nur daran denken: Deklarativ bedeutet, dass jemand anderes die Last trägt, auch wenn es von außen einfach aussieht.
5.2.4.3. Seriell versus Parallel#
Zwei Optionen existieren für die Ausführung von Aufgaben:
Serielle Ausführung: Geräte einzeln verarbeiten. Gerät 1 konfigurieren, auf Abschluss warten, Gerät 2 konfigurieren usw. Sicher (man sieht Fehler sofort und kann stoppen), aber langsam (100 Geräte = 100× die Zeit eines Geräts).
Parallele Ausführung: Mehrere Geräte gleichzeitig verarbeiten. Geräte 1-10 auf einmal konfigurieren, dann 11-20 usw.
flowchart TD
subgraph Serial
S1[Gerät 1] --> S2[Gerät 2] --> S3[Gerät 3]
end
subgraph Parallel
P0[Start] --> P1[Gerät 1]
P0 --> P2[Gerät 2]
P0 --> P3[Gerät 3]
end
Warum Nornir existiert: Ansible war ursprünglich seriell. Für Netzwerkautomatisierung in großem Maßstab war das schmerzhaft langsam. Ansible fügte
strategy: freeund späterforkshinzu, um Parallelismus zu ermöglichen, ist aber immer noch grundlegend für sequentielle Ausführung ausgelegt. Nornir wurde von Grund auf mit Parallelismus entwickelt: Es verwendet standardmäßig Threading, um gleichzeitig gegen mehrere Geräte auszuführen. Das macht es für große Gerätezahlen 10-100× schneller.
Überlegungen zur parallelen Ausführung:
- Control-Plane-Auswirkung: Das gleichzeitige Erreichen von 1000 Geräten kann Management-Netzwerke, Datenquellen und Authentifizierungssysteme oder Geräte-Control-Planes überlasten.
- Abhängigkeitshandhabung: Wenn Geräte voneinander abhängen (Spine vor Leaf), braucht man Reihenfolge. Reine Parallelität funktioniert nicht.
- Fehler-Auswirkungsradius: Wenn die Automatisierung einen Fehler hat, stellt parallele Ausführung ihn auf vielen Geräten bereit, bevor man es bemerkt. Serielle Ausführung scheitert auf Gerät 1, man stoppt, bevor Geräte 2-100 beschädigt werden.
Meine Empfehlung: Parallele Ausführung mit Batching verwenden. Geräte in Gruppen von 10-50 verarbeiten (ich nannte sie früher “Wellen”), den Erfolg jedes Batches verifizieren, bevor man fortfährt. Das balanciert Geschwindigkeit mit Sicherheit. Mehr zu Bereitstellungsstrategien in Kapitel 10.
5.2.4.4. Dry-Run (Plan-Modus)#
Der Dry-Run ist die “Plan”-Phase der Ausführungs-Engine: Änderungen simulieren, ohne Geräte zu berühren, dann einen konkreten Diff und Risiken anzeigen. Ein guter Dry-Run zieht den aktuellen Status, berechnet die genauen gerätespezifischen Operationen, die laufen würden, und validiert Voraussetzungen (Erreichbarkeit, Schema, Abhängigkeitsreihenfolge). Er sollte schnell, deterministisch und reproduzierbar sein, damit Reviewer ihm vertrauen können.
Beispiel (Terraform-Plan für eine AWS-VPC mit überprüfbaren Änderungen):
Terraform will perform the following actions:
# aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ cidr_block = "10.10.0.0/16"
+ enable_dns_support = true
+ enable_dns_hostnames = true
+ tags = {
+ "Name" = "core-vpc"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.Das ist das, worauf Reviewer ihre Genehmigung geben: die genauen Ressourcen und Attribute, die sich ändern würden, ohne die Cloud zu berühren.
In der Praxis ist Dry-Run das, was Genehmigungen bedeutsam macht und Rollbacks weniger wahrscheinlich. Es gibt Menschen einen klaren Überblick über das, was passieren wird, und es gibt der Engine die Möglichkeit, unsichere oder inkonsistente Änderungen früh abzulehnen. Wenn die Plattform Kandidaten-Konfigurationen oder Commit-Check unterstützt, sollte die Engine diese verwenden. Andernfalls ist Dry-Run ein berechneter Diff plus Vorab-Prüfungen, keine Garantie.
Meiner Erfahrung nach ist das Anbieten von Dry-Run-Fähigkeiten in den frühen Tagen eines Automatisierungsprojekts sehr praktisch, um die Akzeptanz von Netzwerkingenieuren zu gewinnen. Später nimmt die Relevanz ab.
5.2.4.5. Resilienz#
Netzwerkausführung ist inhärent unzuverlässig (wie die meisten verteilten Systeme es sind): Geräte starten neu, Konnektivität hakt, und Control-Planes werden überlastet. Andere Abhängigkeiten, wie der Intent-Block, können ebenfalls vorübergehende Probleme haben. Resiliente Ausführung handhabt diese elegant:
Wiederholungslogik:
- Vorübergehende Fehler (Verbindungstimeout, temporäre CPU-Spitze) sollten Wiederholungsversuche mit exponentiellem Backoff auslösen
- Zwischen wiederholbaren Fehlern (Timeout) und dauerhaften Fehlern (Authentifizierungsfehler, Syntaxfehler) unterscheiden
- Wiederholungsversuche begrenzen, um Endlosschleifen zu vermeiden
Timeout-Strategien:
- Verbindungstimeouts: Wie lange auf Geräteantwort warten, bevor aufgegeben wird
- Aufgaben-Timeouts: Wie lange eine vollständige Operation laufen kann (verhindert das Hängenbleiben bei steckenden Geräten)
- Globale Timeouts: Maximale Ausführungszeit für den gesamten Job
Fehlerbehandlung:
- Schnell scheitern: Ein Gerät scheitert, alles abbrechen (sicher, aber ineffizient)
- Weitermachen: Fehler protokollieren, mit anderen Geräten fortfahren (effizient, könnte aber Schaden verbreiten)
- Schwellenwertbasiert: Wenn >10% der Geräte scheitern, stoppen (ausgewogen)
Rollback-Fähigkeiten:
- Konfigurations-Snapshots vor Änderungen erstellen
- Wenn die Ausführung scheitert, Snapshots automatisch wiederherstellen
- Dry-Run-Modus unterstützen: Zeigen, was sich ändern würde, ohne tatsächlich zu ändern
Circuit-Breaker:
- Wenn ein Gerät konsistent scheitert, als ungesund markieren und vorübergehend überspringen
- Verhindert Zeitverschwendung durch wiederholte Verbindungsversuche zu ausgefallenen Geräten
Checkpointing:
- Fortschritt regelmäßig speichern
- Wenn die Ausführung abstürzt, vom letzten Checkpoint fortsetzen statt von vorne beginnen
All das aufzubauen ist schwierig. Die meisten Teams beginnen mit grundlegender Wiederholungslogik und fügen bei Produktionsausfällen Komplexität hinzu.
Ein nützliches Muster: “Sicherheitsmodi” als erstklassige Ausführungszustände behandeln. Beabsichtigte Konfiguration rendern, aktuelle Konfiguration parsen, Fakten erheben, dann nur nach bestandenen Validierungsgattern anwenden (merged/replaced/overridden). Das gibt deterministische Checkpoints, bevor die Produktion berührt wird.
5.2.5. Netzwerkadapter#
Netzwerkgeräte sprechen verschiedene Protokolle. Die Netzwerkadapterschicht abstrahiert diese Unterschiede, sodass die übergeordneten Schichten sich nicht darum kümmern müssen, ob sie mit einem Cisco-Switch über Secure Shell (SSH) oder einem Arista-Switch über eine Representational State Transfer (REST)-Application Programming Interface (API) kommunizieren.
5.2.5.1. Schnittstellen#
Verschiedene Geräte unterstützen verschiedene Verwaltungsschnittstellen:
| Schnittstelle | Beschreibung | Beispiel-Bibliotheken/Werkzeuge | Typische Verwendung |
|---|---|---|---|
| Secure Shell (SSH) / Command Line Interface (CLI) | Universellst, am wenigsten strukturiert (Text ein/aus) | Netmiko (Python), Paramiko (Python), scrapli (Python), scrapligo (Go) | Legacy-Plattformen, anbieterspezifische operative Befehle |
| NETCONF / RESTCONF | Strukturiertes modellgesteuertes Management (YANG-basiert) | ncclient (Python), scrapli-netconf (Python), nemith/netconf (Go) | Deklarative Konfiguration und standardisierte Datenmodelle |
| gRPC Network Management Interface (gNMI) / gNOI | gRPC-basierte Schnittstellen für Konfiguration/Zustand und operative RPCs | pygnmi (Python), gnmic (Go CLI), openconfig/gnmi (Go) | Streaming-Telemetrie und moderne Betriebsworkflows |
| Representational State Transfer (REST)-APIs | HTTP/JSON- oder XML-APIs, oft plattformspezifisch | requests/httpx (Python), net/http + OpenAPI-generierte Clients (Go) | Controller- und Cloud-/Netzwerkplattform-APIs |
| JSON-RPC / Anbieter-gRPC | Strukturierte RPC-Muster für bestimmte Netzwerkbetriebssysteme | Arista eAPI (JSON-RPC), Anbieter-gRPC-SDKs | Schnelle Remote-Prozedurausführung mit strukturierten Payloads |
Manche Bibliotheken bieten eine Abstraktionsschicht mit einer gemeinsamen Schnittstelle über Plattformen hinweg:
- NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support): Python-Bibliothek, die eine einheitliche API über Anbieter hinweg bereitstellt.
- Unterstützt Cisco, Arista, Juniper und andere
- Unter der Haube werden geeignete Protokolle verwendet (Secure Shell (SSH), Application Programming Interface (API), NETCONF)
- Anwendungsfall: Multi-Vendor-Umgebungen, in denen konsistenter Automatisierungscode gewünscht wird
- Pybatfish: Keine Gerätetransport-Bibliothek, aber ein starker Begleiter für Ausführungssicherheit. Ein praktisches Muster ist “Plan/Anwenden mit NAPALM oder Ansible, Netzwerkverhalten vor und nach Änderungen mit Pybatfish validieren.”
Warum eine Abstraktionsschicht verwenden? Anstatt verschiedenen Code für Cisco und Juniper zu schreiben, gibt NAPALM eine API. Man ruft get_facts() auf und NAPALM findet heraus, wie Gerätefakten abzurufen sind, ob es ein Cisco-IOS-Gerät (über Secure Shell (SSH)), Arista EOS (über eAPI) oder Juniper Junos (über NETCONF) ist. Der Kompromiss: Abstraktion verbirgt anbieterspezifische Funktionen. Für gängige Operationen (Konfiguration lesen, Konfiguration pushen, Fakten abrufen) ist es großartig. Für fortgeschrittenere Operationen oder exotische Anbieterfunktionen kehrt man zu nativen Schnittstellen zurück, weil diese wahrscheinlich nicht implementiert sind.
5.2.5.2. Operationen#
Netzwerkausführung ist nicht nur Konfigurationsmanagement:
| Operationstyp | Was es abdeckt | Hinweise |
|---|---|---|
| Konfigurationsänderungen | Vollständige Konfigurationen/Snippets/deklarativen Status pushen; Merge/Replace/Delete-Modi | Häufigster Operationstyp und am besten von Werkzeugen unterstützt |
| Zero-Touch Provisioning (Zero Touch Provisioning (ZTP)) | Automatisiertes Onboarding beim ersten Boot | Erfordert DHCP + Bootstrap-Server (TFTP/HTTP/HTTPS) und Geräteunterstützung |
| Dateiübertragungen | Images hochladen, Protokolle/Backups herunterladen | Gängige Protokolle: SCP, SFTP, TFTP, HTTP |
| Geräteoperationen | Neustart/Reload, operative Befehle (Ping/Traceroute), Backups | Häufig für Day-2-Betrieb und Behebung |
| Rollback | Konfiguration auf vorherigen bekannt-guten Zustand zurücksetzen | Nativer Rollback auf manchen Plattformen; Backup-Wiederherstellung auf anderen |
Jeder Operationstyp hat seine eigenen Fehlermodi und benötigt spezifische Behandlung. Software-Upgrades benötigen Vorab-Prüfungen (genug Speicherplatz?), Nachher-Prüfungen (hat das Gerät korrekt gebootet?) und Rollback-Pläne (wenn Upgrade scheitert, altes Image neu laden). Die Ergebnisse sollten der Orchestrierung für Entscheidungen zur Verfügung gestellt werden, während die Ausführung lokale Leitplanken und Wiederholungsversuche handhaben kann.
Wo Validierung und Rendering hingehören: Der Source of Truth besitzt Absicht und (optional) vorgerenderte Konfigurationen. Die Ausführung besitzt gerätespezifische Sicherheitsprüfungen und operative Validierung (Erreichbarkeit, Vor-/Nachher-Prüfungen). Die Orchestrierung entscheidet wann validiert und was mit Ergebnissen getan wird (genehmigen, pausieren, Rollback oder eskalieren). Als einfache Regel: Validierung, die Workflows ändert, gehört zur Orchestrierung; Validierung, die Geräteaktionen ändert, gehört zur Ausführung.
5.2.6. Lösungen#
Viele Werkzeuge existieren für die Netzwerkausführung, und deren Vergleich hilft, die Abwägungen zu verstehen:
| Werkzeug | Ausführungsmodell und Stärken | Am besten geeignet für | Haupteinschränkungen |
|---|---|---|---|
| Ansible | DSL (YAML), agentlos, großes Modul-Ökosystem, stark für gemischte Server/Netzwerk-Automatisierung | Teams, die schnelle Erfolge und breite Plattformunterstützung wollen | In großem Maßstab braucht es Tuning; komplexe Logik kann in YAML schwer wartbar werden |
| Terraform | Deklaratives IaC (HCL), starke Diff/Plan-Engine, zustandsbehaftete Workflows, exzellente Cloud-Integration | Teams, die Terraform bereits für Infrastruktur standardisieren | Netzwerk-Provider-Reife variiert; Status-Management fügt Betriebsaufwand hinzu; schwächer für Day-2-Betrieb |
| Salt | Python-basiert mit Agent- oder Agentless-Optionen, ereignisgesteuerte Architektur, starke Skalierungseigenschaften | Bestehende Salt-Umgebungen oder ereignislastige Betriebe | Kleinere Netzwerkautomatisierungs-Community und steileres Onboarding |
| Nornir | Python-zuerst Framework, Thread-Parallelismus, hochflexibel, einfacheres Debugging und schnell | Python-fähige Teams mit benutzerdefinierten oder leistungssensitiven Anforderungen | Weniger vorgefertigte Komponenten; mehr Engineering-Eigenverantwortung erforderlich |
| Benutzerdefiniertes Python/Go | Maximale Kontrolle und Designfreiheit für domänenspezifische Logik | Sonderfälle, interne Plattformen und hochspezialisierte Workflows | Man verantwortet alles selbst: Standards, Zuverlässigkeitsmuster, Tests und Lebenszyklusunterstützung |
| Anbieter-Controller | Absichts- und Richtlinien-Controller mit anbietereigenen Workflows (Beispiele: Cisco Catalyst Center, Aruba Central, Juniper Mist) | Teams, die sich um ein Anbieter-Ökosystem mit starken Controller-APIs standardisieren | Weniger portable Muster in Multi-Vendor-Umgebungen |
Viele Teams verwenden je nach Anwendungsfall und Netzwerkinfrastruktur mehrere Werkzeuge.
5.2.7. Zero Touch Provisioning#
Zero Touch Provisioning (ZTP) ist ein eigenständiges Ausführungsmuster, bei dem ein Gerät zum ersten Mal bootet und automatisch seine vollständige Konfiguration abruft und anwendet, ohne menschliches Eingreifen am Gerät. Der Datenfluss unterscheidet sich strukturell von Day-2-Operationen und verdient es, als benanntes Architekturmuster behandelt zu werden.
Der ZTP-Fluss
flowchart LR
A[Gerät bootet\nkeine Konfiguration] --> B[DHCP weist\nManagement-IP\nund Bootstrap-URL zu]
B --> C[Gerät holt\nBootstrap-Konfiguration\nvom Server]
C --> D[Gerät authentifiziert\nsich beim SoT und\nManagement-Netzwerk]
D --> E[Orchestrator erkennt\nneues Gerät, löst\nvollständigen Bereitstellungsjob aus]
E --> F[Executor wendet\nvollständige Absicht aus SoT an]
Die wichtigste Erkenntnis ist, dass der Bootstrap-Schritt bewusst minimal gehalten wird: Gerade genug Konfiguration, um das Gerät ins Management-Netzwerk zu bringen und die Authentifizierung zu ermöglichen. Die vollständige Bereitstellung läuft danach als Standard-Executor-Job, der vollständige Absicht aus dem Source of Truth zieht. Das bedeutet, dass ZTP dieselbe Ausführungspipeline wie Day-2-Operationen wiederverwendet, anstatt ein separates Bereitstellungssystem zu erfordern.
Gängige ZTP-Muster
| Muster | Wie es funktioniert | Abwägung |
|---|---|---|
| DHCP + statische Datei | DHCP verweist auf eine statische Konfigurationsdatei pro Gerät (abgeglichen über MAC oder Seriennummer) | Einfach zu implementieren; zieht nicht aus dem SoT; skaliert schlecht |
| DHCP + dynamische Generierung | Bootstrap-Server fragt SoT ab und generiert gerätespezifische Initialkonfiguration zur Anforderungszeit | SoT-gesteuert von Tag eins; erfordert, dass das Gerät im SoT eingetragen ist, bevor es bootet |
| OS-Image + Konfiguration | Gerät lädt sowohl OS-Image als auch Konfiguration während des Bootens herunter (notwendig für Geräte, die eine OS-Bereitstellung erfordern) | Handhabt Bare-Metal- oder Werksreset-Geräte; erhöht die Komplexität des Bootstrap-Servers |
ZTP führt eine Sequenzierungsabhängigkeit ein: Das Gerät muss im Source of Truth eingetragen sein, bevor es physisch bootet, sonst hat der Bootstrap-Server keine Daten, aus denen er eine Konfiguration generieren kann. Im Campus-Szenario wird das durch die ServiceNow-zu-Nautobot-Synchronisierung gehandhabt: Wenn ein Switch als Asset in ServiceNow hinzugefügt wird (bevor er am Standort ankommt), erstellt Nautobot automatisch den Gerätedatensatz mit Standort, Rolle und Anbieter. Wenn der Switch bootet, ist der SoT bereits bereit.
5.2.8. Hybrid- und Cloud-Ausführung#
Der Executor muss zunehmend gleichzeitig in zwei grundlegend verschiedenen Umgebungen arbeiten: traditionelle Netzwerkgeräte und Cloud-native Plattformen. Diese Umgebungen haben verschiedene API-Paradigmen, Authentifizierungsmodelle und Fehlermodi. Sie identisch zu behandeln führt zu fragiler Automatisierung; sie als völlig separate Systeme zu behandeln dupliziert Aufwand und schafft inkonsistenten Betrieb.
Das Divergenzproblem
| Dimension | Netzwerkgeräte | Cloud-Plattformen |
|---|---|---|
| API-Stil | SSH, NETCONF, gNMI (zustandsbehaftet, langlebige Verbindungen) | REST/HTTP (zustandslos, kurzlebige Anfragen) |
| Auth-Modell | Gemeinsam genutzte Zugangsdaten (Benutzername/Passwort, SSH-Schlüssel) | Temporäre Tokens, Service-Accounts, Instance-Rollen (AWS SigV4, Azure AD, GCP-Service-Accounts) |
| Operationsabschluss | Normalerweise synchron (der Befehl gelingt oder scheitert, bevor die Sitzung endet) | Oft asynchron (API gibt “akzeptiert” zurück, erfordert Polling für den endgültigen Status) |
| Fehler-Ambiguität | Eine abgebrochene NETCONF-Sitzung ist ein klarer Fehler | Ein Cloud-API-Timeout hat die Änderung möglicherweise angewendet oder nicht; man muss abfragen, um es herauszufinden |
| Idempotenz-Ansatz | Imperativ als Standard; Deklarativ erfordert sorgfältiges Modul-Design | Nativ deklarativ auf den meisten Plattformen (Terraform, CloudFormation, Pulumi) |
Die empfohlene Architektur
Intent (SoT) und Orchestrierung vereinheitlicht lassen. Dieselbe Geschäftsanfrage, die ein VLAN auf Campus-Switches erstellt, muss möglicherweise auch eine Security Group in AWS erstellen. Der Source of Truth hält beides. Der Orchestrator koordiniert beides. Nur auf der Netzwerkadapter-Schicht (5.2.5) divergiert der Ausführungspfad: Ein Adapter handhabt NETCONF/Ansible gegen Campus-Switches; ein anderer handhabt Terraform oder Cloud-Provider-APIs gegen die Cloud-Umgebung.
Das bedeutet, dass der Auswirkungsradius einer Cloud-API-Änderung und einer Netzwerkgeräteänderung von denselben Genehmigungen und Audit-Trails geregelt wird, was das korrekte Architekturergebnis ist, auch wenn die Protokolle völlig unterschiedlich sind.
Die Secrets-Manager-Strategie muss sowohl langlebige Netzwerkgeräte-Zugangsdaten als auch kurzlebige Cloud-Tokens aufnehmen. Für Cloud-Plattformen sollten Zugangsdaten beim Job-Start generiert und niemals gespeichert werden. Die meisten Cloud-Provider bieten dafür Mechanismen (AWS Instance Profiles, Azure Managed Identities, GCP Workload Identity). Netzwerkgeräte-Zugangsdaten verbleiben in Vault und werden zur Laufzeit injiziert. Der Executor sollte unabhängig vom Zieltyp niemals Zugangsdaten zwischen Job-Läufen halten.
5.2.9. Sicherheitsüberlegungen#
Der Executor ist die Komponente in der Architektur, die Schreibzugriff auf das Netzwerk hat. Er kann Konfigurationen pushen, Dienste neu starten, Firmware upgraden und Routing-Richtlinien über Hunderte von Geräten gleichzeitig ändern. Das macht seine Sicherheitsposition folgenreicher als fast jede andere Komponente, und dennoch wird er architektonisch am häufigsten vernachlässigt. Ein kompromittierter oder falsch konfigurierter Executor ist kein Datenpannenrisiko; er ist ein Netzwerkausfallrisiko.
Zugangsdaten-Management
Zugangsdaten für Netzwerkgeräte dürfen niemals in Playbooks, Vorlagen, Job-Definitionen oder der Versionskontrolle erscheinen. Das Muster ist unkompliziert: Secrets in einem dedizierten Secrets-Manager speichern (HashiCorp Vault, AWS Secrets Manager, CyberArk) und sie zur Laufzeit in die Umgebung des Executors injizieren. Der Executor holt Zugangsdaten beim Job-Start; er hält sie nicht dauerhaft.
Das bedeutet auch, dass die Rotation von Zugangsdaten betrieblich sicher wird. Wenn Gerätekennwörter rotiert werden, was in einem regelmäßigen Zeitplan erfolgen sollte, nimmt der Executor beim nächsten Lauf neue Zugangsdaten auf, ohne dass eine Bereitstellung oder Neukonfiguration erforderlich ist.
Minimale Rechte pro Operation
Nicht jede Ausführung braucht dieselbe Zugriffsebene. Leseoperationen (Fakten erheben, Dry-Run-Prüfungen, Vorab-Bereitstellungsvalidierung) sollten schreibgeschützte Zugangsdaten verwenden. Schreiboperationen sollten auf den Änderungstyp beschränkte Zugangsdaten verwenden: Ein Job, der VLAN-Änderungen bereitstellt, sollte keine Zugangsdaten haben, die BGP-Konfigurationsänderungen erlauben. Wo die Netzwerkplattform rollenbasierte Zugangskontrolle unterstützt (Arista-Rollen, Cisco-Privilegstufen, NETCONF-Zugangskontrolle), sollte diese verwendet werden, um den Auswirkungsradius einer kompromittierten Sitzung zu begrenzen.
Im Campus-Beispiel bedeutet das, dass ein VLAN-Bereitstellungsjob auf einem Arista-Switch eine Rolle verwendet, die VLAN- und Interface-Konfiguration erlaubt, aber keine Routing-Protokollkonfiguration oder Management-Plane-Einstellungen berühren kann.
Trennung der Zuständigkeiten
Wer die Ausführung auslösen kann und wer die Automatisierungslogik ändern kann, sollten verschiedene Rollen mit verschiedenen Zugriffskontrollen sein. Ein Betreiber, der einen VLAN-Bereitstellungsjob genehmigt und startet, braucht keinen Zugriff auf die Ansible-Rollen oder Playbook-Vorlagen, die ihn implementieren, und sollte ihn auch nicht haben. In AWX und AAP wird das durch Rollenzuweisungen durchgesetzt: “Job Launcher” kann vorab genehmigte Job-Templates starten; “Project Editor” kann die zugrunde liegende Automatisierungslogik ändern.
Diese Trennung ist am wichtigsten, wenn Automatisierung für hochwirksame Operationen verwendet wird. Die Person, die ein Firmware-Upgrade über 800 Switches initiiert, sollte nicht auch die Person sein, die das Upgrade-Playbook geschrieben hat, oder zumindest sollte ein zweiter Reviewer das Playbook genehmigt haben, bevor es für den Produktionseinsatz verfügbar ist.
Anforderungen an den Audit-Trail
Jedes Ausführungsereignis muss mit genügend Details protokolliert werden, um zu rekonstruieren, was passiert ist: Wer den Job ausgelöst hat, welches Job-Template verwendet wurde, welche Geräte anvisiert wurden, welche Parameter übergeben wurden, was das Ergebnis für jedes Gerät war und zu welchem Zeitstempel. Protokolle müssen für den für die Organisation geltenden Compliance-Zeitraum aufbewahrt werden, typischerweise 12 bis 24 Monate für Change-Management in regulierten Branchen.
Das ist in den meisten Unternehmensumgebungen nicht optional. Change-Management-Prozesse erfordern einen rückverfolgbaren Datensatz, der ein Change-Ticket mit einem spezifischen Ausführungsereignis und einem spezifischen Satz von Geräteänderungen verknüpft. Diesen Audit-Trail von Anfang an in den Executor einzubauen, statt ihn später nachzurüsten.
Netzwerksegmentierung der Automatisierungsinfrastruktur
Der Executor und seine Control-Plane (AWX, Ansible Control Nodes) sollten in einem Management-Netzwerksegment sitzen. Ausführungsverkehr zu Geräten sollte wo verfügbar über das Out-of-Band-Management-Netzwerk fließen, nicht durch dieselbe Datenebene, die der Executor möglicherweise modifiziert. Eingehender Zugriff zum Auslösen von Jobs sollte Authentifizierung erfordern und von nicht vertrauenswürdigen Netzwerken nicht erreichbar sein.
Ein praktischer Fehlermodus, den es zu vermeiden gilt: Ein Executor, der vom Produktions-Benutzer-VLAN erreichbar ist, bedeutet, dass jeder kompromittierte Host in diesem VLAN potenziell Netzwerkänderungen auslösen könnte. Management-Plane-Zugriff gehört in ein Management-Plane-Netzwerk.
5.3. Implementierungsbeispiel#
5.3.1. Anwendungsfall: Automatisierte VLAN-Bereitstellung über ein heterogenes Campus-Netzwerk#
Wir setzen mit dem Campus-Netzwerk aus Kapitel 4 fort. Die VLAN-Servicedefinition (ihre ID, Subnetz, anbieterspezifische Konfigurationsvorlagen und Ziel-Switch-Gruppen) ist jetzt im Source of Truth gespeichert. Dieses Kapitel konzentriert sich darauf, wie der Ausführungsblock diese Absicht aufgreift und zuverlässig über alle 800 Switches bereitstellt.
Szenario: Ein Geschäftsteam beantragt ein neues VLAN für eine neue Anwendung. Die Anfrage kommt über ein Ticketing-System mit Details: VLAN-ID, Name, Campus-Standorte und Genehmigung. Der Netzbetrieb stellt dieses VLAN über Arista-, HPE- und Cisco-Access-/Distribution-Switches bereit, verifiziert die Konnektivität und meldet Erfolg.
Anforderungen:
- VLAN-Konfiguration parallel auf mehrere Switches bereitstellen
- Vorab-Bedingungen verifizieren (VLAN existiert nicht bereits, Switches sind erreichbar)
- Dry-Run durchführen, um zu zeigen, was sich ändern würde
- Tatsächliche Bereitstellung mit Rollback-Fähigkeit bei Fehlern ausführen
- Post-Bereitstellung verifizieren (VLAN ist aktiv, keine Fehler)
5.3.2. Lösungsarchitektur#
Bevor man in Ausführungsdetails eintaucht, ein Blick auf die Gesamtarchitektur:
- Source of Truth: NetBox (speichert Inventar, VLAN-Definitionen)
- Orchestrierung/Auslösung: AWX Workflow Template Koordination (API-Launch, Webhook-Launch, geplanter Launch)
- Observability: Liefert Echtzeit-Daten für Entscheidungen
- Ausführung:
- Ausführungs-Engine: Ansible Job-Templates/Aufgaben (Vorab-Prüfung, Dry-Run, Bereitstellen, Verifizieren, Rollback)
- Datenintegration: NetBox Inventory Plugin in Ansible/AWX
- Netzwerkadapter: Ansible-Module für Cisco IOS XE, Arista EOS und HPE/Aruba
- Status-Management: AWX Job- und Workflow-Status pro Phase + pro-Host-Ergebnisse, mit Rollback-Aufgabe bei Fehlerpfaden
Diese Lösung dient Illustrationszwecken; sie ist keine universelle Empfehlung.
5.3.3. Implementierungsablauf#
Dies läuft als AWX-Workflow mit mehreren Aufgabenknoten:
- Eine VLAN-Absichtsänderung in NetBox löst AWX über Webhook aus
- AWX-Workflow startet und führt Inventarsynchronisierung (NetBox) durch
- Vorab-Prüfungsjob validiert Erreichbarkeit, vorhandenen VLAN-Status und Standort-Leitplanken
- Dry-Run-Job rendert anbieterspezifische Aufgaben, ohne Änderungen anzuwenden
- Genehmigungsknoten (optional) gatet Produktionsausführung
- Bereitstellungsjob wendet VLAN-Absicht in parallelen Batches über Anbieter an
- Verifizierungsjob bestätigt operativen und beabsichtigten Status
- Bei Fehlern läuft Rollback-Job nur für den betroffenen Bereich
- Observability sammelt Vor-/Nachher-Daten zur Unterstützung der abschließenden Validierung
- Abschließende Validierung läuft und die Ausführungszusammenfassung wird veröffentlicht
flowchart TD
A[NetBox VLAN-Absichtsänderung] --> B[Webhook an AWX]
B --> C[AWX Workflow Start]
C --> E[Inventarsynchronisierung von NetBox]
E --> F[Vorab-Prüfungsjob]
F --> G[Dry-Run-Job]
G --> H[Genehmigungsknoten]
H --> I[Bereitstellungsjob]
I --> J[Verifizierungsjob]
J --> N[Netzwerkdaten sammeln]
N --> L[Abschließende Validierung]
L --> M[Ticket aktualisieren und Bericht erstellen]
F -->|fehlgeschlagen| X[Stoppen und Validierungsfehler zurückgeben]
I -->|fehlgeschlagene Hosts| Y[Rollback-Job für betroffene Geräte]
Y --> J
F --> N
%% --- Styles ---
classDef sot fill:#cfe8ff,stroke:#0b5fb3,stroke-width:2px;
classDef orch fill:#ffe0cc,stroke:#c24b00,stroke-width:2px;
classDef exec fill:#d7f4e1,stroke:#0f7a3b,stroke-width:2px;
classDef obs fill:#ffd6d6,stroke:#b22222,stroke-width:2px;
class A sot;
class B,C,E,H,L,M orch;
class F,G,I,J,Y,X exec;
class N obs;
5.3.4. Lösungszusammenfassung#
Diese Implementierung demonstriert alle wesentlichen Ausführungsfähigkeiten:
- Datenintegration: Zieht Inventar und Absicht aus NetBox über dynamisches Inventar
- Auslösung: AWX-Workflow unterstützt API/Webhook/Zeitplan sowie genehmigungsgesteuerte Ausführung
- Status-Management: AWX-Workflow-/Job-Status verfolgt Fortschritt und Fehlerbereiche; Rollback-Pfad ist explizit
- Engine: Ansible handhabt parallele Ausführung (konfiguriert über
forks/Batching), Fehlerbehandlung und Dry-Run - Netzwerkadapter: Anbietereigene Ressourcenmodule bilden eine Absicht auf verschiedene Plattformen ab (
cisco.ios.ios_vlans,arista.eos.eos_vlansund HPE/Aruba-Collection-Module) - Observability: Vor-/Nachher-Datenerhebung unterstützt abschließende Validierung und Berichterstattung
Resilienz-Funktionen:
- Vorab-Prüfungen verhindern die Bereitstellung auf nicht erreichbare Geräte oder die Erstellung doppelter VLANs
- Dry-Run zeigt Änderungen vor der Anwendung
- Sicherheits-Checkpoints verwenden Ressourcenmodul-Zustände (
rendered,parsed,gathered) vor Anwendungszuständen (merged,replaced,overridden) - Idempotente Module machen erneute Ausführungen sicher
- Post-Verifizierung erkennt stille Fehler
- Rollback: Dedizierter AWX-Rollback-Knoten begrenzt Rollback auf den betroffenen Gerätebereich
Skalierungsüberlegungen:
- Parallele Ausführung über
forks: 50verarbeitet 50 Switches gleichzeitig - Für größere Bereitstellungen (500+ Switches) in Gruppen aufteilen und Ansible Tower/AWX für Workflow-Management verwenden
- Rate-Limiting hinzufügen, wenn Control-Plane oder Authentifizierungssysteme die Last nicht bewältigen können
5.4. Zusammenfassung#
Der Ausführungsblock ist der Ort, wo Netzwerkautomatisierung greifbar wird: Konfigurationen werden gepusht, Geräte werden neu gestartet, Änderungen passieren. Aber zuverlässige Ausführung ist mehr als das Senden von Befehlen über Secure Shell (SSH).
Es beginnt mit Datenintegration und Auslösung, dann hängt es von Status-Management ab (Idempotenz, Rollback und transaktionsähnliche Sicherheit), einer fähigen Engine (serielle/parallele Entscheidungen, Dry-Run/Plan, Resilienz) und einer Netzwerkadapterschicht, die Protokollunterschiede über Anbieter hinweg verbirgt. Observability speist Validierung und Leitplanken, während Orchestrierung entscheidet, wann fortgefahren oder gestoppt werden soll. Das Tooling ist weniger wichtig als die Ausführungsmuster: Daten integrieren, absichtsvoll auslösen, deterministisch ausführen, Ergebnisse validieren und einen sauberen Rollback-Pfad beibehalten.
Klein anfangen und bewusst skalieren: Ein Workflow, eine Geräteklasse und klare Vor-/Nachher-Prüfungen. Batching, Rate-Limits und stärkere Validierung hinzufügen, wenn der Auswirkungsradius wächst. Ausführung ist mächtig und riskant; gründlich testen, schrittweise ausrollen, ständig überwachen und immer für Rollback planen.
Referenzen und weiterführende Literatur#
- Network Programmability and Automation: Skills for the Next-Generation Network Engineer, 2. Ausgabe. O’Reilly Media, 2023. Matt Oswalt, Christian Adell, Scott S. Lowe und Jason Edelman. Kapitel 10 (Automatisierungswerkzeuge) und Kapitel 12 (Automatisierungsarchitektur).
- Network Automation Cookbook, 2. Ausgabe. Packt Publishing, 2024. Christian Adell und Jeff Kala.
- Ansible Network Automation Dokumentation: https://docs.ansible.com/ansible/latest/network/
- Mastering Python Networking, 4. Ausgabe. Packt Publishing, 2023. Eric Chou
- NAPALM Dokumentation: https://napalm.readthedocs.io/
- Nornir Dokumentation: https://nornir.readthedocs.io/
- Terraform Network Infrastructure Automation: https://www.terraform.io/use-cases/network-infrastructure-automation
💬 Found something to improve? Send feedback for this chapter