Bei der Administration einer großen Zahl von Servern ist ein zentrales Konfigurations-Management irgendwann unabdingbar. Dieser Artikel beschreibt in einer ersten Einführung das in Ruby geschriebene Framework Puppet.
Teil unseres Tagesgeschäfts ist es, beliebig große Server-Installationen zu verwalten und zu warten. Gerade bei großen Clustern heißt dies, eine Vielzahl von Maschinen mit fast identischer Konfiguration nebeneinander zu betreiben. Ohne eine zentralisierte, automatisierte Konfigurations-Verteilung ist dies kaum machbar – an dieser Stelle tritt Puppet auf den Plan.
Wie auch andere Konfigurations-Management-Werkzeuge greift Puppet auf einen zentralen Server zurück, der die Konfiguration verwaltet. Dort fragen die „Clients“ verschlüsselt die Konfiguration ab, und spielen Sie gemäß der Vorgaben des Servers ein, verändern Rechte, führen Befehle aus, etc. Die Vorteile liegen auf der Hand:
Puppet besteht aus einem zentralen Server, Puppet-Master genannt, und den Clients, genannt Nodes. Diese melden sich beim Master an, und fragen dort nach der aktuellen Konfiguration. Der Master gibt diese an die Nodes weiter – die Möglichkeiten der Anweisungen des Masters sind schier unbegrenzt:
Im Prinzip kann alles mit der Übergabe von Dateien vom Server an die Node erledigt werden, doch ist dies in komplexen Setups weder übersichtlich noch vereinfachend. Gerade die Abstraktion von System-Aufgaben (Dienste neu starten, Paket-Versionen sicherstellen, Nutzer einrichten, etc.) ohne das direkte Überschreiben von Dateien hilft ungemein beim Konfigurieren komplexer Systeme.
Für die Installation benötigt man einen zentralen Puppet-Master, der die Konfiguration verwaltet: apt-get install puppetmaster
Puppet geht davon aus, dass alle beteiligten Rechner FQDNs haben, dies sollte in einem korrekt gewarteten Netzwerk aber eh der Fall sein!
Auf jedem zu verwaltenden Rechner wird ein Puppet-Client mit apt-get install puppet
installiert.
Die Puppet-Nodes suchen automatisch nach dem Rechner, der auf den Namen puppet auflöst, so lange der Name korrekt auf den Hauptserver zeigt, brauchen sie nicht weiter konfiguriert werden.
Beim Puppet-Master muss der Dateiserver noch korrekt konfiguriert werden, der wie oben beschrieben Dateien an die Nodes übergeben kann. Je nach Anspruch können die Dateien dabei nah bei der weiteren Konfiguration gehalten werden, oder aber zentral in einem externen Archiv untergebracht werden. Für unser Beispiel werden wir die zu verteilenden Dateien nah bei der eigentlichen Konfiguration halten, ganz so, wie es auch im Best Practice Guide und in der Anleitung Module Configuration der Puppet-Dokumentation beschrieben wird.
Daher reicht es, in der Datei /etc/puppet/fileserver.conf folgende Konfiguration vorzunehmen:
[modules] allow 192.168.0.1/24 allow *.credativ.de
Um eine Server-Konfiguration durch Puppet erledigen zu lassen, ist es am Besten, diese in Aufgabenbereiche oder Themen zu unterteilen, wie zum Beispiel „ssh“, „logs“, „apache“, etc. Diese Bereiche werden in Puppet als „Module“ bezeichnet, und sind der Kern von Puppets Konfigurationsverwaltung. Den Aufbau eines Modules beschreiben wir hier anhand einer fiktiven SSH-Konfiguration und halten uns dabei eng an den Best Practice Guide.
Es sei angemerkt, dass die tatsächliche Konfiguration von SSH durch Puppet an einigen Stellen dynamischer wäre, hier wird nur ein vereinfachter Weg gezeigt.
Der Anspruch des SSH-Moduls ist:
Um diesen Ansprüchen gerecht zu werden, erstellen wir die notwendigen Verzeichnisse des Moduls:
mkdir -p /etc/puppet/modules/ssh/manifests mkdir -p /etc/puppet/modules/ssh/files
Der Ordner Mainfests enthält die eigentlichen Konfigurations-Anweisungen des Moduls, der Ordner files hält Dateien vor, die an die Nodes ausgeliefert werden sollen.
Die Konfigurations-Anweisungen des Modules finden sich in der Datei init.pp im Ordner manifests. Die Gruppe von Anweisungen, um die obigen Ziele 1.-4. zu erfüllen, wird dort als „Klasse“ zusammen gefasst. Die Klasse enthält selbst wiederum Untersektionen, sogenannte Types. In unserem Fall findet sich für jedes vorher definierte Ziel ein Type:
class ssh{ package { "openssh-server": ensure => latest, } file { "/etc/ssh/sshd_config": owner => root, group => root, mode => 644, source => "puppet:///ssh/sshd_config", } service { ssh: ensure => running, hasrestart => true, subscribe => File["/etc/ssh/sshd_config"], } file { "/home/credativ/.ssh": path => "/home/credativ/.ssh", owner => "credativ", group => "credativ", mode => 600, recurse => true, source => "puppet:///ssh/ssh", ensure => [directory, present], } }
jeder Type setzt eine gänzlich andere Aktion auf dem Node um:
package
Hier wird sicher gestellt, dass das Paket openssh-server in der neuesten Version installiert ist.
file
Eine Datei auf der Node wird durch die Version vom Server überschrieben und mit entsprechenden Rechten versehen.
service
Der Dienst sshd muss laufen, und wird notfalls gestartet. Falls außerdem die Datei /etc/ssh/sshd_config aktualisiert wird, wird auch der Dienst neu gestartet.
file
Hier taucht noch einmal der Type „file“ auf – es wird aber nicht eine einzelne Datei übertragen, sondern gleich ein ganzes Verzeichnis.
Damit das Modul auch korrekt arbeitet, müssen die beim Type „file“ definierten Dateien und Verzeichnisse auch unter /etc/puppet/modules/ssh/files/ zu finden sein.
Wir haben nun drei Elemente: den Puppet-Master, die Nodes, und die Module. Nun muss die Zuweisung erfolgen, welche Nodes welche Module aufrufen sollen. Dafür muss zuerst das Modul in der Datei /etc/puppet/manifests/modules.pp aktiviert werden:
import "ssh"
Die Zuweisung zu den einzelnen Nodes erfolgt in der Datei /etc/puppet/manifests/nodes.pp. Diese legt für jede Node fest, welches Modul geladen wird. Außerdem gibt es für alle nicht weiter spezifizierten Nodes einen Default-Eintrag, und zu guter Letzt können auch Einträge von anderen abgeleitet werden. Um also für alle Nodes das Modul „rsyslog“ zu laden, aber nur für die Node „external“ das Modul „ssh“, sieht der Eintrag wie folgt aus:
node default { include rsyslog } node 'external' inherits default { include ssh }
Damit ist Puppet fertig konfiguriert, und nimmt sofort seine Arbeit auf.
Die Kommunikation zwischen Master und Node verläuft verschlüsselt. Um dies zu gewährleisten, müssen Nodes auf dem Master zertifiziert werden. Dies ist möglich, nachdem ein Node das erste Mal eine Anfrage an den Master gestellt hat – der Master setzt diesen Node dann auf wait, und stellt ihm so lange keine Daten zur Verfügung. Erst, wenn die Node durch einen Admin verifiziert wurde, wird die Node frei geschaltet. Mit # puppetca --list
wird die Liste der noch zu verifizierenden Nodes angezeigt, verifiziert wird mit: # puppetca --sign external.example.com
Bei Bedarf kann dieser Prozess weiter verfeinert werden.
Die hier vorgestellten Beispiele sind natürlich stark vereinfacht. Im Real-Betrieb würde die SSH-Konfiguration komplexer sein, und Schlüssel würden nicht gerade mit dem Type „file“ statisch verteilt werden. Aus diesen Beispielen lassen sich aber leicht weitere Module ableiten, und die an vielen Stellen verlinkte Konfiguration tut ihr Übriges, damit der geneigte Leser sich tiefer in die Materie einarbeiten kann.
Wir hier bei credativ haben mit Puppet mittlerweile sehr umfangreiche und sehr gute Erfahrungen gemacht, leisten an vielen Ecken Support und Beratung für Puppet und merken, wie die Nachfrage steigt. Puppet ist derzeit auf der Überholspur, und es wird spannend sein zu beobachten, wie sich der Platzhirsch cfengine angesichts dieser Konkurrenz verhält.
Dieser Artikel wurde ursprünglich geschrieben von Roland Wolters.
Kategorien: | HowTos |
---|---|
Tags: | Puppet |