Moin Eike,
das hört sich sehr gut an. Ich habe mich über die Feiertage auch intensiv mit Puppet auseinandergesetzt. Gerne helfe ich dir hier weiter mit, da ja Tarek im Prüfungsstress ist.
Wo kannst du denn Hilfe gebrauchen?
Stefan
Am 03.01.2016 um 21:11 schrieb Eike Baran:
Hallo,
tl;dr: wer ahnung von puppet hat, möge sich mal das schaubild unter https://wiki.nordwest.freifunk.net/Puppet ansehen und beurteilen bzw. ggf. verbessern/alternativen vorschlagen. Alle anderen dürfen natürlich gerne aus Interesse mitlesen oder es ignorieren, ich wollte nur mal die aktuellen Überlegungen kommunizieren.
wie ihr ja wisst, sind wir nun seit einigen Wochen dabei, die Verwaltung der Server durch Puppet übernehmen zu lassen. Grundsätzlich bietet Puppet dafür auch tolle Möglichkeiten, jedoch bin ich nun auch an einigen Stellen an Puppets, bzw. genauer gesagt Hieras Grenzen gestoßen.
In Kürze ist Hiera eine art Datenbank, die auf *.yaml-Dateien basiert und die Konfigurationsdaten für die sogn. Puppet-Module enthält, welche wiederum jeweils eine Funktionseinheit eines Servers darstellen (zB apt-Paket und dessen Konfiguration). Die Puppet-Module enthalten also entsprechende Templates für die Konfigurationsdateien, die genauen, teils universellen (zB MTU, ssh-keys oder interface-namen), teils serverspezifischen Werte (zB Adressbereiche oder fastd-private-key).
Gemäß einer definierbaren Reihenfolge (einer HIERArchie) läd hiera bei einem puppet-Durchlauf nun die korrekten werte aus der datenbank. So schaut hier zunächst, ob es node-spezifische Werte (in den srvXX.ffnw.de.yaml-Dateien) gibt. Falls nein, geht es in der Hierarchie eine ebene abwärts und es werden die allgemeingültigen Werte (aus der Datei common.yaml) geliefert. Wie gesagt, grundsätzlich klingt das sehr fein, der Teufel steckt aber in den Details:
Es gibt im Grunde 3 verschiedene Lookup-Typen in hiera: hiera(), hiera_merge() und hiera_hash(). Verwendet wird meist der erste, welcher genau einen Treffer zu dem gesuchten key liefert, nämlich den, der in der Hierarchie am weitesten oben steht. Dummerweise gibt es Situationen, da reicht das nicht bzw. führt zu redundanzen und doppelt eingetragenen werten, die natürlich, was die Wartung angeht, scheiße sind.
Beispiel: Für die Konfiguration von dhcp über dnsmasq muss in Hiera ein Datensatz liegen, der im yaml-Format etwa so aussieht:
dnsmasq: dhcp_range_start: 192.168.0.10 dhcp_range_end: 192.168.0.100 lease_time: 15m
Hierbei sind die Grenzen des Ranges natürlich serverspezifisch, die lease_time aber tendenziell auf allen Servern gleich und würde in der serverspezifischen hiera-datei diese nur künstlich aufblasen. Mit hiera_hash() kann man nun folgendes tun: man definiert in common.yaml:
dnsmasq: lease_time: 15m
und in srvXX.ffnw.de.yaml:
dnsmasq: dhcp_range_start: 192.168.0.10 dhcp_range_end: 192.168.0.100
Ruft man nun in einem Modul hiera_hash('dnsmasq') auf, erhält man ein Objekt, was den obigen vollständigen Datensatz enthält. Dabei entsteht in den einzelnen serverspezifischen *.yaml keine Redundanz/potenzielle Fehlermöglichkeit.
Leider ist die hiera_hash()-Funktion sowie eine zusätzliche Einstellung des 'deeper merging', die hierfür in bestimmten Fällen benötigt wird, noch recht neu und wird in vorhandenen Puppet-Modulen aus der Puppet-Forge auch nur selten verwendet. Ein aktuell von uns verwendeter "workaround" ist nun, die dnsmasq-Konfiguration vollständig in common.yaml unterzubringen und zwar in dieser Form: dnsmasq: dhcp_range_start: "%{hiera('range_start')}" dhcp_range_end: "%{hiera('range_end')}" lease_time: 15m
und in der srvXX.ffnw.de folgendes zu speichern: range_start: 192.168.0.10 range_end: 192.168.0.100
Damit hat man die lease_time nicht mehr in den serverspezifischen werten und die start- und endadresse wird mit einem verschachtelten lookup eben aus dieser datei geholt. (Das Beispiel hier ist kein gutes, weil gerade dnsmasq über genau diese funktion verfügt, aber es ist hier ja nur für das verständnis). Aber auch dieser Ansatz hat seine grenzen: Diese verschachtelte hiera()-Funktion kann nur Strings, d.h. keine Nummern, keine Booleans oder gar Objekte liefern, ebenso ist das Verhalten, wenn die verschachtelte Abfrage keinen Treffer findet, so, dass die übergeordnete Abfrage sehr wohl Erfolg hat und dann mit einem leeren String arbeitet, was manchmal sehr problematisch sein kann.
Neben dieser - ich nenn sie mal - hiera-eingeschränkter-lookup-problematik gibt es noch eine zweite, die unangenehm sein kann: Man definiert in der Datei <environment_name>/manifests/sites.pp, welcher server, welche Puppet-Module bekommen soll, mit sogn. include-anweisungen der Form:
include dnsmasq include ntp include ...
Das gilt dann entweder nur für einen Server oder für alle oder für diejenigen, deren fqdns ein bestimmten Regex matchen. Anschließend müssen dann auch für alle die genannten module valide daten in hiera hinterlegt werden, sonst schlägt der durchlauf fehl. Dort nun Gruppen für Supernodes und andere Aufgaben anzulegen ist - was ich bisher weiß - nur auf Umwegen möglich, es gibt hier aber die Methode, den Befehl hiera_include statt der obigen, klassichen Include-direktiven zu verwenden, das sieht dann so aus:
hiera_include('classes')
Und nun kann man wiede per hiera in common.yaml oder anderen Dateien der Hierarchie Klassen angeben, also zb:
classes:
- ntp
- dnsmasq
Das schöne hierbei ist, dass diese Klassen tatsächlich gemerged werden, d.h. sowohl die Klassen, die in common.yaml angegeben sind als auch die, die in srvXX.ffnw.de angelegt sind, werden "in einen topf" geschmissen und dann alle eingebunden. Wodurch man nun recht bequem einzelnen servern nur bestimmte Module zuweisen kann. Was nun noch fehlt, ist ein Mechanismus, um Servern bestimmte Rollen zu geben, zB "webserver" oder "supernode" oder "webserver und supernode", ohne hier wiederum die gemeinsamen hiera-werte in die serverspezifischen yaml-dateien knallen zu müssen, sondern sie in einer gemeinsamen webserver.yaml oder supernodes.yaml zusammenzuhalten. Hierfür habe ich mir das auf der Wiki-Seite dargestellte Rollen-Konstrukt überlegt, das ähnlich wie bei der Nginx-Config mit "available" und "enabled" ordnern arbeitet und zum aktivieren einer Rolle aus "available" nach "enabled" symlinkt.
Desweiteren möchte ich zukünftig dann klar zwischen Modulen aus der Forge und selbstentwickelten trennen, wobei die selbstentwickelten künftig nicht mehr das in den hiera-dateien eingebettete "%{hiera(KEY)}", sondern hiera_hash()-basierte Abfragen nutzen sollen, wann immer Daten aus unterschiedlichen Ebenen gemischt werden müssen, da diese bisherige methode die genannten großen Probleme mit sich bringt. Die Forge-Module werden dann auch nicht mehr in $codedir/environments/{dev,prod}/modules, sonder in $codedir/modules liegen - damit ist dann leichter unterscheidbar, was selbstgebaut ist und was nicht und es kommt nicht zu etwaigen problemen, wenn zB in dev ein Forge-Modul geupdatet wird, aber selbiges in prod vergessen wird, sondern alles greift immer auf exakt dasselbe Modul zu.
Soviel dazu, wie gesagt, wenn es Möglichkeiten gibt, die genannten Probleme zum umschiffen, ohne hier mit etwas gewöhnungsbedürftigen Symlink-Konstrukten herunmzubasteln, gerne her damit, ich hänge da nicht dran, sehe derzeit nur keine gleichwertige Alternative.
Viele Grüße, Eike
Dev mailing list Dev@lists.ffnw.de https://lists.ffnw.de/mailman/listinfo/dev