Automatisierung gehört im Rechenzentrum zum guten Ton. Puppet gilt als Platzhirsch und darf von sich behaupten, bei Unternehmen wie Google im Einsatz zu sein. Ansible ist eine schlanke Alternative.
“Früher war alles besser.” Das geflügelte Wort steht dafür, dass der Mensch gern in Erinnerungen an die vermeintlich gute alte Zeit schwelgt. Systemadministratoren bilden da keine Ausnahme: Gerne erinnert sich mancher an die Zeit zurück, in der IT-Setups noch aus einer überschaubaren Anzahl von Servern bestanden, deren händische Verwaltung problemlos möglich war. Diese Zeiten sind vorbei: Die großen Hoster zum Beispiel haben Tausende Hosts unter ihren Fittichen und betreuen viele der Rechner im Auftrag ihrer Kunden.
Mit Handarbeit ist da kein Blumentopf mehr zu gewinnen: Längst haben Werkzeuge für Konfigurationsmanagement und Automatisierung die Kontrolle in vielen Rechenzentren übernommen. Wohl jeder Admin kennt die einschlägigen Lösungen: Puppet [1] und Chef [2] sind die Goliaths ihrer Art und halten zusammen ein stattliches Stück vom großen Automatisierungskuchen.
Für Puppet gilt allerdings auch, dass viele Admins dem Werkzeug regelmäßig Tod und Teufel an den Hals wünschen: Zu komplex soll es sein und zu weit habe es sich von seinen ursprünglichen Idealen fortbewegt. Da kommt ein junger Wilder wie Ansible [3] gerade recht: Dieses Tool verspricht eine bessere Automatisierungslösung zu sein, die deutlich leichter zu durchdringen ist und dabei keine Funktionalität vermissen lässt. Der folgende Artikel stellt Puppet als Vertreter der hergebrachten Automatisierer und Ansible als den Underdog gegenüber und streicht Gemeinsamkeiten wie Unterschiede heraus. Wofür ist Ansible tatsächlich zu gebrauchen? Kann es Puppet ernsthaft gefährlich werden?
Selbst in den schon beschworenen goldenen Zeiten, als jeder Server noch eine echte Handaufzucht war, konnte es nötig sein, die Konfigurationsdateien einzelner Dienste auf mehreren Servern synchron zu halten. Diverse Bastellösungen auf Basis von Rsync oder SCP legen davon Zeugnis ab. Sogar eigene Werkzeuge entstanden für diesen Zweck: Die Wiener HA-Spezialisten von Linbit etwa entwickelten Csync2 – ein Tool, dessen einzige Aufgabe war, Dateien in HA-Clustern auf demselben Stand zu halten.
Dass all diese Ansätze nur Krücken waren, wurde schnell offensichtlich. Als 2005 die erste Version von Puppet erschien, wirkte das von den Entwicklern gegebene Versprechen revolutionär: Konfigurationsdateien, die an zentraler Stelle hinterlegt und gepflegt werden, ließen sich mit Puppet auf eine beliebige Anzahl von Servern verteilen.
Auch Puppet war mal Underdog
Bald konnte Puppet nicht nur Dateien ausrollen, sondern auf den betroffenen Servern gleich auch einzelne Befehle aufrufen, zum Beispiel um Pakete nachzuinstallieren. Die Puppet-Entwicklung ging mit riesigen Schritten voran: Die eigene Deklarationssprache DSL erlaubte es, generische Module zu verfassen, die einzelne Aufgaben erledigten. Fertige Module konnten Admins mit der Öffentlichkeit teilen und so einen Beitrag zur Welt der Open-Source-Systemadministration leisten.
Puppet selbst wuchs und wuchs. Diverse wichtige Features hielten im Laufe der Entwicklung Einzug, etwa die Möglichkeit, die Konfiguration aus externen Quellen zu beziehen. Die ENCs – das steht für External Node Classifiers – existieren heute in verschiedenen Formen und Geschmacksrichtungen von unterschiedlichen Herstellern. Eigentlich ist also alles bestens im Puppet-Land. Wie erklärt sich dann aber die offene Abneigung vieler Admins gegenüber dem Tool?
Mit der Zeit wurde Puppet immer komplexer
Der mit Abstand am häufigsten formulierte Vorwurf an Puppet ist, dass sich das Werkzeug von seinen ursprünglichen Zielen wegbewegt hat und im Rechenzentrum eine eierlegende Wollmilchsau sein will. Die hohe Komplexität lasse Puppet, so seine Kritiker, für die effektive Nutzung unbrauchbar werden. Wo eigentlich die Reduktion von Komplexität das Ziel von Automatisierung sei, füge Puppet noch Komplexität hinzu. Die schon erwähnten Puppet-Module sind dafür ein gutes Beispiel: In der Anfangszeit von Puppet gab es für die meisten Probleme genau ein Modul. Wer also mit Puppet Rsyslog installieren wollte, fand dafür im Netz genau eine Lösung.
Der Haken an der Sache: Die Entwickler entwarfen Module mit Blick auf exakt ein Einsatzszenario. Entsprechend schlecht fügen sie sich in andere Setups ein. Bald griffen Forks vorhandener Module um sich: Wer eine Modifikation eines vorhandenen Moduls für seine lokale Installation benötigte, forkte es und veröffentlichte den Fork im Anschluss selbst. Wer heute nach Puppet-Modulen für Rsyslog sucht, ist erst mal damit beschäftigt, sich durch die einzelnen Alternativen zu ackern und das beste Modul für den eigenen Zweck zu finden. Schon die Frage, welche Linux-Distribution ein Puppet-Modul unterstützen soll, entscheidet oft über Wohl und Wehe.
Das Puppet-Projekt hat selbst versucht, diesem Treiben Einhalt zu gebieten: Puppetforge [4] gilt als autoritative Quelle für Puppet-Module und zeichnet auch solche Module gesondert aus, die Puppet selbst pflegt. Allerdings kann auch jeder andere Nutzer seine Module auf Puppetforge hochladen. Letztlich trägt Puppetforge zur Verwirrung also eher bei, als sie zu verhindern.
Dann ist da noch das leidige Thema der Modulpflege: Diverse Module, die sich im Netz finden, sind älteren Datums und funktionieren auf neueren Systemen oft nicht oder nicht mehr richtig. In jedem Einzelfall muss der Admin selbst herausfinden, ob das bei einem bestimmten Modul so ist oder nicht.
ENC? Oje!
Auch an den External Node Classifiers, die nach Aufruf eine Beschreibung des Node im Yaml-Format zurückliefern, lassen viele Admins kein gutes Haar. In den letzten Jahren hat sich das von Puppet selbst entwickelte Hiera [5] zum Quasi-Standard für die Verwaltung Site-spezifischer Daten außerhalb von Manifests entwickelt. Hiera selbst (Abbildung 1)ist allerdings alles andere als leicht zu durchdringen: Es kennt mehrere Wertetypen wie Strings, Hashes und Arrays und kombiniert diese in teils schwer nachvollziehbarer Weise. Obendrein lässt Hiera chaotische Konfigurationen zu: Gerade Hiera-Quellen, die im Laufe vieler Jahre entstanden, sind für Neueinsteiger kaum zu durchschauen.
Die Puppet-Module für die Cloudlösung Open Stack sind dafür exemplarisch: In Open Stack gibt es viele Dienste – und für jeden gibt es ein eigenes Puppet-Modul. Open-Stack-Dienste nutzen eine Ini-Syntax für ihre Konfiguration. Die Open-Stack-Puppet-Module akzeptieren Konfigurationsparameter etwa aus Hiera und wandeln diese im Prozess per Ruby-Modul in Ini-Syntax um. Effektiv erstellt der Admin also eine vollständige Open-Stack-Konfiguration – allerdings im Yaml-Format in Hiera. Die Puppet-Module für Open Stack generieren daraus letztlich die Konfigurationen der Open-Stack-Dienste. Garniert ist das Ganze mit allerlei Voodoo, das die Module im Hintergrund treiben.
Einerseits kommen so auch jene Admins zu einem Open Stack, die sich mit der Cloudlösung noch nicht so sehr beschäftigt haben. Auf der anderen Seite entsteht so kaum das notwendige Verständnis, um eine so große Lösung wie Open Stack sinnvoll zu betreuen. Spätestens wenn die Cloud zum ersten Mal den Geist aufgibt, ist Holland in Not.
Architektonische Schwächen
Hinzu kommen diverse Designprobleme, die bei Puppet – wie bei fast jeder anderen Lösung – erst im Lauf der Zeit erkennbar wurden. Eine große Schwierigkeit in Puppet ist etwa die fehlende Option, das Ausführen einzelner Befehle über mehrere Hosts innerhalb des Clusters zu koordinieren.
Theoretisch ist Puppet zwar idempotent; jeder Befehl lässt sich also beliebig oft ausführen, ohne zu Problemen zu führen. Praktisch kommt es aber fast immer zu Schwierigkeiten, wenn das Ausführen von Befehlen auf mehreren Hosts koordiniert ablaufen soll. Denn hier sind viele Abhängigkeiten zu beachten: Bevor sich etwa ein Webserver sinnvoll betreiben lässt, ist auf einem anderen Host möglicherweise eine Datenbank auszurollen und in ihr auch ein entsprechendes Datenbankschema zu installieren.
Das Ausrollen einer HA-Datenbank, etwa MySQL mit Galera, ist zwar problemlos möglich. Doch wenn es darum geht, das Datenbankschema zu installieren, kümmert sich der Admin besser händisch darum. Sonst steht in der Datenbank im schlimmsten Falle Murks, nachdem sich zwei Puppet-Instanzen beim gleichzeitigen Verändern der Datenbank in die Haare gekriegt haben.
Selbst die Definition von Abhängigkeiten auf demselben Host führt in unschöner Regelmäßigkeit zu Problemen. Die Auswirkungen bekommen vor allem jene Admins zu spüren, die sich mit Cloudsetups beschäftigen: Hier existieren sowohl Abhängigkeiten innerhalb eines Hosts wie auch über mehrere Hosts hinweg.
Das Master-Agent-Modell als Schwachstelle
Mindestens genauso wenige Freunde hat die Puppet-Architektur. Auf jedem Host, der unter Puppets Fuchtel steht, läuft mindestens ein Puppet-Agent. Der ist dafür verantwortlich, die Konfiguration des Servers in den Soll-Zustand zu versetzen. Es existieren zwei Ansätze: Entweder ist auf jedem Host die gesamte Puppet-Konfiguration vorhanden. Der Agent greift dann lediglich lokal auf sie zu und setzt sie entsprechend um. Alternativ dazu lässt sich Puppet mit einem Master-Server betreiben: Mit diesem verbinden sich dann die Agents auf den unterschiedlichen Hosts, um sich ihre Konfiguration abzuholen.
Beide Wege haben eklatante Nachteile: Wer einen Puppet-Agent lokal und ohne Master nutzen will, muss Sorge dafür tragen, dass alle relevanten Konfigurationsfiles für Puppet auf diesem Host vorhanden sind. Nicht wenige Puppet-Installationen rufen beim Start des Agent auf einem Host erst mal Git auf, um sich selbst in den jeweils aktuellen Zustand zu versetzen.
Wer sich für die Variante mit dem Master-Server entscheidet, holt sich damit als Alternative einen echten Ressourcenfresser ins Setup. Nicht selten führt eine große Puppet-Konfiguration in Verbindung mit vielen Agents, die sich zeitgleich an den Puppet-Master wenden, zu quälend langsamem Vorankommen. So entsteht beim Admin schnell der Eindruck, dass er es falsch macht – egal wie er es anstellt.
Ansible betritt die Bühne
Ob es 2012 eine der Hauptmotivationen der Ansible-Entwickler war, den Entwicklern von Puppet und anderen Lösungen mit ähnlichen Problemen eins auszuwischen, ist nicht überliefert. Klar ist hingegen, dass Ansible sich vor allem durch reduzierte Komplexität von seinen Konkurrenten am Markt unterscheiden will. Mit dieser Strategie hat das Projekt offenbar Erfolg: Red Hat kaufte die Firma hinter Ansible im Oktober 2015 für 150 Millionen Dollar. Auch in Raleigh ist man von den Vorzügen der Software also offenbar überzeugt. Aber was unterscheidet Ansible von Puppet & Co.?
Ansible versteht sich als Werkzeug, das maßgeblich drei Aufgaben verbindet: die Verteilung von Software, die Ad-hoc-Ausführung von Befehlen und das Management von Konfigurationsdateien. Tatsächlich ist der Anspruch also nicht so großartig anders als der, den Puppet oder Chef an sich selbst formulieren.
SSH statt spezieller Protokolle
Schon auf den ersten Blick fallen aber diverse Unterschiede zu Puppet oder Chef auf. Frappierend ist etwa die Art und Weise, wie Ansible die Verwaltung einzelner Hosts sicherstellt. Denn ein Server-Client-Prinzip wie bei Puppet ist Ansible fremd. Der Weisheit letzter Schluss ist bei Ansible stattdessen simples SSH: Lediglich auf einem Server muss die Ansible-Konfiguration vorhanden sein.
Von dort aus springt Ansible selbst per SSH auf die einzelnen Rechner und führt auf ihnen die gewünschten Konfigurationsschritte aus. Es nutzt also weder ein eigenes Protokoll, noch braucht es eine eigene Client-Software (Abbildung 2). Damit ist es dem Admin sogar möglich, den Ansible-Haupthost selber mittels Ansible von einem anderen Rechner – etwa dem eigenen Notebook – aus zu installieren.
Außerdem erfüllt Ansible dank SSH hier bereits den Punkt der Ad-hoc-Verwaltung: Zumindest am Anfang war es nämlich eine durchaus wichtige Ansible-Funktion, einen durch den Admin festgelegten Befehl zentral auf allen Servern des Serververbunds zu starten. Freilich erledigen das sonst auch separate Tools wie PSSH. Aber falls ein Admin ohnehin zu Ansible greift, lohnt es sich, diese Funktionalität ebenfalls auszunutzen.
Playbooks statt Manifeste
Ansibles Art, die Konfiguration der verwalteten Maschinen zu organisieren, ist in anderer Hinsicht anders als bei Puppet. Das geht bei der Nomenklatur los: Bei Puppet reden Admins von Manifesten, vergleichbar damit sind in Ansible die so genannten Playbooks. Der Name kommt nicht von ungefähr: Im IT-Kontext ist der Begriff Playbook schließlich entsprechend geprägt. Gemeint ist damit meist eine Art Emergency-Handbuch: Was hat ein Admin in einer bestimmten Situation zu tun?
Ganz so dramatisch ist die Ansible-Interpretation eines Playbook zwar nicht. Aber der Name passt trotzdem: Die Struktur eines Ansible-Playbook ist nämlich der eines klassischen Erste-Hilfe-Eintrags sehr ähnlich. Das Listing 1 enthält ein funktionierendes Playbook, das einen Webserver installiert.
Listing 1
provision.yaml für die Rolle Webserver
01 ---
02 - hosts: backend
03 sudo: yes
04 roles:
05 - role: webserver
06 vhosts:
07 - { hostname: 'webserver.local', dir: '/var/www/htdocs' }
Die Idee ist klar erkennbar: Der Eintrag hinter »name« legt fest, was das entsprechende Kommando tut, und zwar in verständlichen Worten. Dann folgt eine Liste der Dateien, die zu verändern sind, sowie der Befehle, die zu dem Ansible-Kommando gehören. Praktisch sind Playbooks also Listen von Einzelbefehlen, die in spezifischer Reihenfolge auszuführen sind (Abbildung 3).
Das Ansible-Rollenmodell
Per se ist so ein Playbook freilich unnütz: Schließlich ist es noch nicht mit irgendeinem Host assoziiert. Um diese Verbindung herzustellen, nutzt Ansible ein Rollenmodell, das dem von Puppet in vielerlei Hinsicht recht ähnlich ist: Pro Host möchte Ansible wissen, welche Rollen auf ihm zu installieren sind.
Listing 2
main.yaml
01 ---
02 - name: Install Apache
03 apt: pkg=apache2-mpm-prefork state=present
04
05 - name: Delete default Apache vhost
06 file: path=/etc/apache2/sites-enabled/000-default state=absent
07 notify: Restart Apache
08
09 - name: Generate Vhosts
10 template:
11 src=vhost.conf
12 dest=/etc/apache2/sites-enabled/{{ item.hostname }}.conf
13 with_items: vhosts
14 notify: Restart Apache
Das Listing 2 enthält eine Rollendefinition, die dem Host »backend« die Rolle »webserver« zuweist. Die Rollendefinition ist auch der Ort, um Parameter für die Konfiguration der zugedachten Rolle zu übergeben – im Beispiel die auf dem Server anzulegenden Virtual Hosts samt ihrem Hauptverzeichnis. Das Gezeigte passt zu dem Beispiel in Listing 3 und legt die entsprechenden Werte fest.
Die Inventory-Datei
Auffällig anders ist wieder die Art, wie Ansible die Hosts verzeichnet, die es beackert: Eine so genannte Inventory-Datei listet lediglich die Hosts und die IP-Adressen auf, unter denen der jeweilige Hosts zu erreichen ist – fertig ist der Lack. Listing 3 zeigt eine vollständige Inventory-Definition, die für das konkrete Beispiel den Host »backend« anlegt.
Listing 3
Ansible-Inventory
01 [backend] 02 192.168.0.1 # Backend-Server
Dynamische Inventories
Ansible will auch eine Orchestrierungslösung sein und richtet sich zum Beispiel an Kunden, die VMs in Cloudumgebungen betreiben. Für praktisch jede Umgebung finden Admins im Ansible-Handbuch [6] ein Skript, das die Inventory-Datei für Ansible auf Grundlage der Informationen generiert, die in der Cloud für den Nutzer hinterlegt sind. Eben weil Ansible regelmäßig per SSH alle Rechner aufs Neue durchgeht, lässt sich das Inventory auch im laufenden Betrieb durch eine neue Version ersetzen. Frickelwerk wie bei Puppets Datenbank und den üblichen, automatisch signierten SSL-Zertifikaten ist also nicht notwendig.
Abhängigkeiten auch über Hostgrenzen
Eines der größten Horrorszenarien im Umgang mit Puppet ist das Ausdrücken verlässlicher Abhängigkeiten zwischen einzelnen Aufgaben. Zwar existieren die Schlüsselwörter »requires« , »before« und »after« , doch wer die benutzt, läuft schnell Gefahr, den Überblick zu verlieren. Völlig unmöglich sind – wie bereits erwähnt – Abhängigkeiten über mehrere Hosts hinweg. Ansible ist anders: Auf Basis des simplen Rollenmodells mit passenden Playbooks führen Admins nach Belieben Aufgaben in deterministischer Reihenfolge aus – auch spezifisch auf einzelnen Hosts.
Maßgeblich dafür ist die Execution-Order: Ansible führt Playbooks grundsätzlich in der Reihenfolge aus, die in ihnen bestimmt ist. Wenn also die Reihenfolge eines Playbook festlegt, dass die Rolle »database« auf die Hosts »db1« und »db2« beschränkt ist und die Rolle »webserver« auf den Host »backend« , arbeitet Ansible die Schritte genau so ab. Erst wenn die Rolle »database« auf den beiden Zielhosts funktioniert, beginnt es überhaupt damit, den »backend« -Server zu bearbeiten. Für Admins, die regelmäßig in Puppets Dependency-Hölle geraten sind, ist gerade dieser Umstand eine große Erleichterung beim Umstieg auf Ansible.
Erweiterungen per Modul
Admins, die auf den Hosts spezifische eigene Befehle ausführen möchten, tun das mit Ansible-Modulen (Abbildung 4). Module sind kleine Programme, die Ansible im Rahmen eines Ansible-Run auf den Zielhost kopiert. Dort werden sie im Anschluss ausgeführt und schließlich auch wieder gelöscht. Der Clou: Module lassen sich in jeder beliebigen Sprache verfassen, die einzige Voraussetzung dafür ist, dass die Module beim Aufruf auf dem Zielhost ihre Ausgabe in Json liefern. Der Ruby-Zwang, der bei Puppet-Modulen vorhanden ist, entfällt.
Fast jeder Aspekt der Ansible-Nutzung lässt sich so bestimmen. Module funktionieren obendrein auch auf höheren Ebenen: Wer mit der SSH-Ausführung nicht zufrieden ist, kann etwa ein anderes Transportmodul benutzen, um Ansible seine Befehle auf den Zielhosts ausführen zu lassen.
Fertige Playbooks existieren zuhauf
Gemeinsam haben Puppet und Ansible die Vorteile einer großen Community, die sich darum kümmert, Playbooks für praktisch jede Aufgabe anzubieten. Wie für Puppet existiert auch für Ansible eine vollständige Lösung, um beispielsweise Open Stack sinnvoll zu deployen [7]. Der amerikanische Hosting-Riese Rackspace pflegt den nötigen Code dafür. Ein Ansible-Forge existiert zwar nicht, aber eine Google-Suche mit den entsprechenden Schlüsselwörtern führt in aller Regel zum Erfolg.
Ansible eignet sich übrigens nicht nur, um Linux-Systeme mit SSH zu nutzen. Auch Unterstützung für BSD ist an Bord, und diverse Befehle der Windows Powershell beherrscht Ansible ebenfalls.
Fazit: Ist Ansible das bessere Puppet?
Ansible beeindruckt im direkten Vergleich mit Puppet gleich auf mehreren Ebenen. An erster Stelle ist die Performance des Werkzeugs zu nennen. Ein Puppet-Agent zieht sich in typischen Setups mit einem Puppet-Master beim Start eines Puppet-Run zunächst einmal seine gesamte Konfiguration vom Master und lädt sie sich komplett in den lokalen Cache. Das dauert.
Danach gehen einige Sekunden dafür drauf, dass der Puppet-Master das komplette Manifest für einen Host auf Zuruf erst einmal generieren muss. Erst dann erfolgt die Ausführung – und die nimmt bei großen Manifests gern auch schon mal etliche Minuten in Anspruch.
Ansible ist da merklich flinker: Einmal in Gang gekommen, wickelt das Werkzeug die ausstehenden Arbeiten auf den verschiedenen Hosts deutlich schneller ab, als das die alteingesessene Standardlösung vermag.
Auch die geringe Komplexität der Ansible-Konfiguration verblüfft. Die Playbooks erscheinen klar und strukturiert, sie sind selbst dann nachvollziehbar, wenn man mit Ansible noch nicht viel zu tun hatte. Dass Ansible es gar nicht erst versucht, zu einem Konfigurationskonverter à la Puppet und Hiera zu werden, ist den Entwicklern hoch anzurechnen. Templates geben im typischen Ansible-Playbook den Ton an.
Bei aller Euphorie sei aber auch darauf hingewiesen, dass Ansible deutlich jünger ist als Puppet. Wer die Arbeit mit Hiera bei Puppet gewohnt ist und mag, findet die Struktur der Ansible-Playbooks vermutlich unnötig redundant – gerade für solche Setups hat man bei Puppet Labs ja einmal Hiera erfunden. Hinzu kommt, dass Ansible als Underdog gilt. Selbst nach dem Kauf durch Red Hat haben viele Admins diese Lösung noch nicht recht auf dem Schirm. Daran, dass sich das bald ändern wird, besteht kein ernsthafter Zweifel. Denn Red Hat investiert nicht versehentlich viel Geld in Unternehmen.
Wie viele von den heute zweifellos vorhandenen Ansible-Vorteilen aber übrig bleiben, wenn die Lösung erst mal weiterwächst und nach und nach mehr Features dazukommen, das muss sich erst noch zeigen. Für den Augenblick gilt: Wer eine schlanke Alternative zu Puppet sucht, findet in Ansible vermutlich etwas Passendes.
Infos
- Puppet: https://puppetlabs.com
- Chef: https://www.chef.io/chef
- Ansible: http://www.ansible.com
- Puppetforge: https://forge.puppetlabs.com
- Hiera: http://docs.puppetlabs.com/hiera/1/
- Ansible-Doku: http://docs.ansible.com/ansible/intro.html
- Open Stack mit Ansible: https://github.com/openstack/openstack-ansible










