Konfigurationsmanagement 101: Puppet Manifests schreiben

Einführung

Kurz gesagt, das Serverkonfigurationsmanagement (im Volksmund auch als IT-Automatisierung bezeichnet) ist eine Lösung, mit der Sie Ihre Infrastrukturverwaltung in eine Codebasis verwandeln können. Es beschreibt alle für die Bereitstellung eines Servers erforderlichen Prozesse in einer Reihe von Bereitstellungsskripten, die versioniert und problemlos wiederverwendet werden können. Es kann die Integrität jeder Serverinfrastruktur im Laufe der Zeit erheblich verbessern.

In einem vorheriges Handbuch haben wir über die wichtigsten Vorteile der Implementierung einer Konfigurationsmanagementstrategie für Ihre Serverinfrastruktur gesprochen, wie das Konfigurationsmanagement Tools funktionieren und was diese Tools normalerweise gemeinsam haben.

Dieser Teil der Serie führt Sie durch den Prozess der Automatisierung der Serverbereitstellung mit Puppet, einem beliebten Konfigurationsverwaltungstool, mit dem komplexe Infrastrukturen auf transparente Weise verwaltet und die Konfiguration der Knoten mithilfe eines Masterservers koordiniert werden kann. Wir werden uns auf die Terminologie, Syntax und Funktionen der Sprache konzentrieren, die für die Erstellung eines vereinfachten Beispiels erforderlich sind, um die Bereitstellung eines Ubuntu 18.04-Webservers mit Apache vollständig zu automatisieren.

Dies ist die Liste der Schritte, die wir automatisieren müssen, um unser Ziel zu erreichen:

  1. Aktualisiere den + apt + Cache

  2. Installieren Sie Apache

  3. Erstellen Sie ein benutzerdefiniertes Dokumentstammverzeichnis

  4. Platzieren Sie eine "+ index.html" -Datei im Stammverzeichnis des benutzerdefinierten Dokuments

  5. Wenden Sie eine Vorlage an, um unseren benutzerdefinierten virtuellen Host einzurichten

  6. Starten Sie Apache neu

Wir beginnen mit einem Blick auf die von Puppet verwendete Terminologie, gefolgt von einem Überblick über die wichtigsten Sprachfunktionen, die zum Schreiben von Manifesten verwendet werden können. Am Ende dieses Handbuchs geben wir das vollständige Beispiel weiter, damit Sie es selbst ausprobieren können.

Anfangen

Bevor wir uns näher mit Puppet befassen können, ist es wichtig, dass wir uns mit wichtigen Begriffen und Konzepten vertraut machen, die mit diesem Tool eingeführt werden.

Marionette Begriffe

  • * Puppet Master *: Der Master-Server, der die Konfiguration auf den Knoten steuert

  • * Puppet Agent Node *: Ein Knoten, der von einem Puppet Master kontrolliert wird

  • * Manifest *: Eine Datei, die eine Reihe von Anweisungen enthält, die ausgeführt werden sollen

  • * Ressource *: Ein Teil des Codes, der ein Element des Systems deklariert und angibt, wie sein Status geändert werden soll. Um beispielsweise ein Paket zu installieren, müssen wir eine package-Ressource definieren und sicherstellen, dass ihr Status auf "installiert" gesetzt ist.

  • * Modul *: Eine Sammlung von Manifesten und anderen zugehörigen Dateien, die in vordefinierter Weise organisiert sind, um das Teilen und Wiederverwenden von Teilen einer Bereitstellung zu erleichtern

  • * Klasse *: Genau wie bei normalen Programmiersprachen werden in Puppet Klassen verwendet, um die Bereitstellung besser zu organisieren und die Wiederverwendung von Teilen des Codes zu vereinfachen

  • * Fakten *: Globale Variablen, die Informationen zum System enthalten, z. B. Netzwerkschnittstellen und Betriebssystem

  • * Dienste *: Wird verwendet, um Dienststatusänderungen auszulösen, z. B. Neustarten oder Beenden eines Dienstes

Puppet-Provisionierungen werden mit einer benutzerdefinierten DSL (domänenspezifischen Sprache) geschrieben, die auf Ruby basiert.

Ressourcen

Mit Puppet werden Aufgaben oder Schritte durch Angabe von * Ressourcen * definiert. Ressourcen können Pakete, Dateien, Dienste, Benutzer und Befehle darstellen. Sie haben möglicherweise einen Status, der eine Systemänderung auslöst, wenn sich der Status einer deklarierten Ressource von dem unterscheidet, der sich derzeit auf dem System befindet. Beispielsweise wird eine package-Ressource, die in Ihrem Manifest auf "+ installed +" gesetzt ist, eine Paketinstallation auf dem System auslösen, wenn das Paket zuvor nicht installiert wurde.

So sieht eine package-Ressource aus:

package { 'nginx':
   ensure  => 'installed'
}

Sie können jeden beliebigen Befehl ausführen, indem Sie eine "+ exec +" - Ressource wie die folgende deklarieren:

exec { 'apt-get update':
   command => '/usr/bin/apt-get update'
}

Beachten Sie, dass der Teil "+ apt-get update" in der ersten Zeile nicht die eigentliche Befehlsdeklaration ist, sondern eine Kennung für diese eindeutige Ressource. Häufig müssen wir innerhalb einer Ressource auf andere Ressourcen verweisen, und dafür verwenden wir deren Bezeichner. In diesem Fall lautet der Bezeichner "+ apt-get update", es kann sich jedoch auch um eine andere Zeichenfolge handeln.

Ressourcenabhängigkeit

Beachten Sie beim Schreiben von Manifesten, dass Puppet die Ressourcen nicht in der Reihenfolge bewertet, in der sie definiert sind. Dies ist eine häufige Quelle der Verwirrung für diejenigen, die mit Puppet anfangen. Ressourcen müssen die Abhängigkeiten explizit definieren. Andernfalls kann nicht garantiert werden, welche Ressource zuerst ausgewertet und folglich ausgeführt wird.

Als einfaches Beispiel nehmen wir an, Sie möchten einen Befehl ausführen, müssen jedoch zuerst sicherstellen, dass eine Abhängigkeit installiert ist:

package { 'python-software-properties':
   ensure => 'installed'
}

exec { 'add-repository':
   command => '/usr/bin/add-apt-repository ppa:ondrej/php5 -y'
   require => Package['python-software-properties']
}

Die Option + require + erhält als Parameter einen Verweis auf eine andere Ressource. In diesem Fall beziehen wir uns auf die package-Ressource, die als + python-software-properties gekennzeichnet ist. + Es ist wichtig zu beachten, dass wir, während wir "+ exec ", " package " und dergleichen zum Deklarieren von Ressourcen (mit Kleinbuchstaben) verwenden, wenn wir auf zuvor definierte Ressourcen verweisen, " Exec ", " Package +" und so weiter on (aktiviert).

Angenommen, Sie müssen sicherstellen, dass eine Aufgabe * vor * einer anderen ausgeführt wird. In einem solchen Fall können wir stattdessen die Option "+ vor +" verwenden:

package { 'curl':
   ensure => 'installed'
   before => Exec['install script']
}

exec { 'install script':
   command => '/usr/bin/curl http://example.com/some-script.sh'

Manifest-Format

Manifeste sind im Grunde eine Sammlung von Ressourcendeklarationen mit der Erweiterung "+ .pp ". Im Folgenden finden Sie ein Beispiel für ein einfaches Wiedergabebuch, das zwei Aufgaben ausführt: Es aktualisiert den " apt " - Cache und installiert anschließend " vim +":

exec { 'apt-get update':
   command => '/usr/bin/apt-get update'
}

package { 'vim':
   ensure => 'installed'
   require => Exec['apt-get update']
}

Vor dem Ende dieses Handbuchs werden wir ein realistischeres Beispiel eines Manifests sehen, das im Detail erklärt wird. Der nächste Abschnitt gibt Ihnen einen Überblick über die wichtigsten Elemente und Funktionen, die zum Schreiben von Puppet-Manifesten verwendet werden können.

Manifeste schreiben

Mit Variablen arbeiten

Variablen können zu jedem Zeitpunkt in einem Manifest definiert werden. Die gebräuchlichsten Variablentypen sind Zeichenfolgen und Arrays von Zeichenfolgen. Es werden jedoch auch andere Typen unterstützt, z. B. Boolesche Werte und Hashes.

Das folgende Beispiel definiert eine Zeichenfolgenvariable, die später in einer Ressource verwendet wird:

$package = "vim"

package { $package:
  ensure => "installed"
}

Verwenden von Loops

Schleifen werden normalerweise verwendet, um eine Aufgabe mit unterschiedlichen Eingabewerten zu wiederholen. Anstatt beispielsweise 10 Aufgaben für die Installation von 10 verschiedenen Paketen zu erstellen, können Sie eine einzelne Aufgabe erstellen und eine Schleife verwenden, um die Aufgabe mit allen verschiedenen Paketen zu wiederholen, die Sie installieren möchten.

Der einfachste Weg, eine Aufgabe mit unterschiedlichen Werten in Puppet zu wiederholen, ist die Verwendung von Arrays, wie im folgenden Beispiel:

$packages = ['vim', 'git', 'curl']

package { $packages:
  ensure => "installed"
}

Ab Version 4 unterstützt Puppet zusätzliche Möglichkeiten zum Durchlaufen von Aufgaben. Das folgende Beispiel entspricht dem vorherigen Beispiel, verwendet jedoch diesmal den Iterator "+ each +". Diese Option bietet Ihnen mehr Flexibilität beim Durchlaufen von Ressourcendefinitionen:

$packages.each |String $package| {
 package { $package:
   ensure => "installed"
 }
}

Bedingungen verwenden

Mit Hilfe von Bedingungen kann dynamisch entschieden werden, ob ein Codeblock ausgeführt werden soll oder nicht, beispielsweise basierend auf einer Variablen oder einer Ausgabe eines Befehls.

Puppet unterstützt die meisten bedingten Strukturen, die Sie in traditionellen Programmiersprachen finden können, z. B. die Anweisungen + if / else + und + case +. Darüber hinaus unterstützen einige Ressourcen wie "+ exec +" Attribute, die wie eine Bedingung funktionieren, aber nur eine Befehlsausgabe als Bedingung akzeptieren.

Angenommen, Sie möchten einen Befehl basierend auf einem Fakt ausführen. In diesem Fall müssen Sie zum Testen des Werts einer Variablen eine der unterstützten bedingten Strukturen verwenden, z. B. "+ if / else +":

if $osfamily != 'Debian' {
warning('This manifest is not supported on this OS.')
}
else {
notify { 'Good to go!': }
}

Eine andere häufige Situation ist, wenn Sie die Ausführung eines Befehls auf der Grundlage der Ausgabe eines anderen Befehls konditionieren möchten. In solchen Fällen können Sie "+ onlyif " oder " except " verwenden, wie im folgenden Beispiel. Dieser Befehl wird nur ausgeführt, wenn die Ausgabe von ` / bin / which php +` erfolgreich ist, dh der Befehl wird mit dem Status * 0 * beendet:

exec { "Test":
command => "/bin/echo PHP is installed here > /tmp/test.txt",
onlyif => "/bin/which php"
}

In ähnlicher Weise wird der Befehl immer mit "" ausgeführt, es sei denn, der Befehl unter "" wird erfolgreich beendet:

exec { "Test":
command => "/bin/echo PHP is NOT installed here > /tmp/test.txt",
unless => "/bin/which php"
}

Mit Vorlagen arbeiten

Vorlagen werden normalerweise zum Einrichten von Konfigurationsdateien verwendet, wobei Variablen und andere Funktionen verwendet werden können, um diese Dateien vielseitiger und wiederverwendbarer zu machen. Puppet unterstützt zwei verschiedene Formate für Vorlagen: Embedded Puppet (EPP) und Embedded Ruby (ERB). Das EPP-Format funktioniert jedoch nur mit neueren Puppet-Versionen (ab Version 4.0).

Nachfolgend finden Sie ein Beispiel für eine ERB-Vorlage zum Einrichten eines virtuellen Apache-Hosts unter Verwendung einer Variablen zum Einrichten des Dokumentstamms für diesen Host:

<VirtualHost *:80>
   ServerAdmin webmaster@localhost
   DocumentRoot <%= @doc_root %>

   <Directory <%= @doc_root %>>
       AllowOverride All
       Require all granted
   </Directory>
</VirtualHost>

Um die Vorlage anzuwenden, müssen wir eine Ressource "+ file" erstellen, die den Vorlageninhalt mit der Methode "+ template a" rendert. So würden Sie diese Vorlage anwenden, um den virtuellen Apache-Standardhost zu ersetzen:

file { "/etc/apache2/sites-available/000-default.conf":
   ensure => "present",
   content => template("apache/vhost.erb")
}

Puppet geht beim Umgang mit lokalen Dateien von einigen Annahmen aus, um die Organisation und Modularität durchzusetzen. In diesem Fall würde Puppet nach einer "+ vhost.erb " - Vorlagendatei in einem Ordner " apache / templates +" in Ihrem Modulverzeichnis suchen.

Services definieren und auslösen

Service-Ressourcen werden verwendet, um sicherzustellen, dass Services initialisiert und aktiviert werden. Sie werden auch verwendet, um einen Neustart des Dienstes auszulösen.

Betrachten wir unser vorheriges Beispiel für die Verwendung von Vorlagen, in dem wir einen virtuellen Apache-Host einrichten. Wenn Sie sicherstellen möchten, dass Apache nach einer Änderung des virtuellen Hosts neu gestartet wird, müssen Sie zunächst eine service-Ressource für den Apache-Dienst erstellen. So wird eine solche Ressource in Puppet definiert:

service { 'apache2':
   ensure => running,
   enable => true
}

Wenn Sie nun die Ressource definieren, müssen Sie eine "+ notify +" - Option einfügen, um einen Neustart auszulösen:

file { "/etc/apache2/sites-available/000-default.conf":
   ensure => "present",
   content => template("vhost.erb"),
   notify => Service['apache2']
}

Beispiel Manifest

Schauen wir uns nun ein Manifest an, das die Installation eines Apache-Webservers in einem Ubuntu 14.04-System automatisiert, wie in der Einführung dieses Handbuchs beschrieben.

Das vollständige Beispiel, einschließlich der Vorlagendatei zum Einrichten von Apache und einer vom Webserver bereitgestellten HTML-Datei, finden Sie unter on Github. Der Ordner enthält auch eine Vagrant-Datei, mit der Sie das Manifest in einem vereinfachten Setup mit einer virtuellen Maschine testen können, die von https://vagrantup.com [Vagrant] verwaltet wird.

Nachfolgend finden Sie das vollständige Manifest:

default.pp

$doc_root = "/var/www/example"

exec { 'apt-get update':
command => '/usr/bin/apt-get update'
}

package { 'apache2':
ensure  => "installed",
require => Exec['apt-get update']
}

file { $doc_root:
ensure => "directory",
owner => "www-data",
group => "www-data",
mode => 644
}

file { "$doc_root/index.html":
  ensure => "present",
  source => "puppet:///modules/main/index.html",
  require => File[$doc_root]
}

file { "/etc/apache2/sites-available/000-default.conf":
  ensure => "present",
  content => template("main/vhost.erb"),
  notify => Service['apache2'],
  require => Package['apache2']
}

service { 'apache2':
  ensure => running,
  enable => true
}

Manifest erklärt

Linie 1

Das Manifest beginnt mit der Variablendefinition "+ $ doc_root +". Diese Variable wird später in einer Ressourcendeklaration verwendet.

Zeilen 3-5

Diese * exec * -Ressource führt einen Befehl + apt-get update aus.

Zeilen 7-10

Diese * package * -Ressource installiert das Paket + apache2 + und definiert, dass die Ressource + apt-get update + eine Anforderung ist. Dies bedeutet, dass sie erst ausgeführt wird, nachdem die erforderliche Ressource ausgewertet wurde.

Zeilen 12-17

Wir verwenden hier eine * Datei * -Ressource, um ein neues Verzeichnis zu erstellen, das als unser Dokumentenstamm dient. Die Ressource "+ file " kann zum Erstellen von Verzeichnissen und Dateien sowie zum Anwenden von Vorlagen und Kopieren lokaler Dateien auf den Remote-Server verwendet werden. Diese Aufgabe kann zu jedem Zeitpunkt der Bereitstellung ausgeführt werden, sodass wir hier kein " erfordern +" festlegen mussten.

Zeilen 19-23

Wir verwenden hier eine andere * file * -Ressource, um diesmal unsere lokale * index.html * -Datei in den Dokumentenstamm im Server zu kopieren. Wir verwenden den Parameter "+ source ", um Puppet zu informieren, wo sich die Originaldatei befindet. Diese Nomenklatur basiert auf der Art und Weise, wie Puppet mit lokalen Dateien umgeht. Wenn Sie sich das https://github.com/erikaheidi/cfmgmt/tree/master/puppet/environments/vagrant/modules/main/files[Github-Beispielrepository ansehen, werden Sie sehen, wie die Verzeichnisstruktur erstellt werden sollte damit Puppet diese Ressource findet. Das Dokumentstammverzeichnis muss vor dieser Ressourcenausführung erstellt werden. Aus diesem Grund wird die Option " erfordern +" eingefügt, die auf die vorherige Ressource verweist.

Zeilen 25-30

Eine neue * Datei * -Ressource wird verwendet, um die Apache-Vorlage anzuwenden und den Dienst über einen Neustart zu benachrichtigen. In diesem Beispiel ist unsere Bereitstellung in einem Modul mit dem Namen "* main " organisiert. Aus diesem Grund lautet die Vorlagenquelle " main / vhost.erb *". Wir verwenden eine "+ require " - Anweisung, um sicherzustellen, dass die Template-Ressource erst ausgeführt wird, nachdem das Paket " apache2 +" installiert wurde. Andernfalls ist die von Apache verwendete Verzeichnisstruktur möglicherweise noch nicht vorhanden.

Zeilen 32-35

Schließlich deklariert die Ressource * service * den Dienst + apache2 +, den wir bei einem Neustart von der Ressource benachrichtigen, die die Vorlage für den virtuellen Host anwendet.

Fazit

Puppet ist ein leistungsstarkes Konfigurationsmanagement-Tool, das eine ausdrucksstarke, benutzerdefinierte DSL-Funktion zum Verwalten von Serverressourcen und zum Automatisieren von Aufgaben verwendet. Seine Sprache bietet erweiterte Ressourcen, die Ihren Bereitstellungs-Setups zusätzliche Flexibilität verleihen können. Es ist wichtig zu bedenken, dass Ressourcen nicht in der Reihenfolge ausgewertet werden, in der sie definiert sind. Aus diesem Grund müssen Sie beim Definieren von Abhängigkeiten zwischen Ressourcen vorsichtig sein, um die richtige Ausführungskette festzulegen.

Im next guide of this series werden wir einen Blick auf Chef werfen, ein weiteres leistungsstarkes Konfigurationsmanagement-Tool, das die Vorteile nutzt Die Programmiersprache Ruby zur Automatisierung der Infrastrukturverwaltung und -bereitstellung.