Konfigurationsmanagement 101: Chef-Rezepte schreiben

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

Inprevious guide sprachen wir über die Hauptvorteile der Implementierung einer Konfigurationsverwaltungsstrategie für Ihre Serverinfrastruktur, die Funktionsweise von Konfigurationsverwaltungstools und die Gemeinsamkeiten dieser Tools.

Dieser Teil der Serie führt Sie durch den Prozess der Automatisierung der Serverbereitstellung mit Chef, einem leistungsstarken Konfigurationsverwaltungstool, das die Programmiersprache Ruby nutzt, um die Verwaltung und Bereitstellung der Infrastruktur zu automatisieren. Wir werden uns auf die Sprachterminologie, die Syntax und die Funktionen 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. Aktualisieren Sie den Cache vonapt

  2. Installieren Sie Apache

  3. Erstellen Sie ein benutzerdefiniertes Dokumentstammverzeichnis

  4. Platzieren Sie eineindex.html-Datei im benutzerdefinierten Dokumentstamm

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

  6. Starten Sie Apache neu

Zunächst werfen wir einen Blick auf die von Chefkoch verwendete Terminologie, gefolgt von einem Überblick über die wichtigsten Sprachfunktionen, die zum Schreiben von Rezepten verwendet werden können. Am Ende dieses Handbuchs geben wir das vollständige Beispiel weiter, damit Sie es selbst ausprobieren können.

[.note] #Note: Dieses Handbuch soll Ihnen die Einführung in die Chef-Sprache und das Schreiben von Rezepten zur Automatisierung der Serverbereitstellung ermöglichen. Eine einführende Ansicht von Chefkoch, einschließlich der Schritte, die für die Installation und den Einstieg in dieses Tool erforderlich sind, finden Sie unterChef’s official documentation.
#

Anfangen

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

Chefkoch Begriffe

  • Chef Server: Ein zentraler Server, der Informationen speichert und die Bereitstellung der Knoten verwaltet

  • Chef Node: Ein einzelner Server, der von einem Chef Server verwaltet wird

  • Chef Workstation: Ein Controller-Computer, auf dem die Bereitstellungen erstellt und auf den Chef Server hochgeladen werden

  • Recipe: Eine Datei, die eine Reihe von Anweisungen (Ressourcen) enthält, die ausgeführt werden sollen. Ein Rezept muss inCookbook enthalten sein

  • Resource: Ein Teil des Codes, der ein Element des Systems deklariert und welche Aktion ausgeführt werden soll. Um beispielsweise ein Paket zu installieren, deklarieren wir einepackage-Ressource mit der Aktioninstall

  • Cookbook: Eine Sammlung von Rezepten und anderen zugehörigen Dateien, die auf vordefinierte Weise organisiert sind, um das Teilen und Wiederverwenden von Teilen einer Bereitstellung zu erleichtern

  • Attributes: Details zu einem bestimmten Knoten. Attribute können automatisch sein (siehe nächste Definition) und können auch innerhalb von Rezepten definiert werden

  • Automatic Attributes: Globale Variablen, die Informationen über das System enthalten, z. B. Netzwerkschnittstellen und Betriebssystem (in anderen Tools alsfacts bezeichnet). Diese automatischen Attribute werden von einem Tool namensOhai erfasst

  • Services: Wird verwendet, um Änderungen des Dienststatus auszulösen, z. B. das Neustarten oder Stoppen eines Dienstes

Rezept Format

Kochrezepte werden mit Ruby geschrieben. Ein Rezept ist im Grunde eine Sammlung von Ressourcendefinitionen, mit denen eine schrittweise Anweisungsfolge erstellt wird, die von den Knoten ausgeführt wird. Diese Ressourcendefinitionen können für mehr Flexibilität und Modularität mit Ruby-Code gemischt werden.

Unten finden Sie ein einfaches Beispiel für ein Rezept, dasapt-get update ausführt und anschließendvim installiert:

execute "apt-get update" do
 command "apt-get update"
end

apt_package "vim" do
 action :install
end

Rezepte schreiben

Mit Variablen arbeiten

Lokale Variablen können in Rezepten als reguläre lokale Ruby-Variablen definiert werden. Das folgende Beispiel zeigt, wie eine lokale Variable erstellt wird, die später in einer Ressourcendefinition verwendet wird:

package  = "vim"

apt_package package do
 action :install
end

Diese Variablen haben jedoch einen begrenzten Gültigkeitsbereich und sind nur in der Datei gültig, in der sie definiert wurden. Wenn Sie eine Variable erstellen und global verfügbar machen möchten, damit Sie sie aus einem Ihrer Kochbücher oder Rezepte verwenden können, müssen Siecustom attribute definieren.

Attribute verwenden

Attribute stellen Details zu einem Knoten dar. Chef hat automatische Attribute, die von einem Tool namens Ohai erfasst werden und Informationen über das System enthalten (z. B. Plattform, Hostname und Standard-IP-Adresse). Sie können jedoch auch Ihre eigenen benutzerdefinierten Attribute definieren.

Attribute haben unterschiedliche Prioritätsstufen, die durch den von Ihnen erstellten Attributtyp definiert werden. default Attribute sind die häufigste Wahl, da sie bei Bedarf immer noch von anderen Attributtypen überschrieben werden können.

Das folgende Beispiel zeigt, wie das vorherige Beispiel mit einem Knotenattribut vondefaultanstelle einer lokalen Variablen aussehen würde:

node.default['main']['package'] = "vim"

apt_package node['main']['package'] do
 action :install
end

In diesem Beispiel sind zwei Details zu beachten:

Die empfohlene Vorgehensweise beim Definieren von Knotenvariablen besteht darin, sie als Hashes zu organisieren, wobei das aktuell verwendete Kochbuch als Schlüssel verwendet wird. In diesem Fall haben wirmain verwendet, da wir ein Kochbuch mit demselben Namen haben. Dies vermeidet Verwirrung, wenn Sie mit mehreren Kochbüchern arbeiten, die möglicherweise ähnlich benannte Attribute haben.
Beachten Sie, dass wir beim Definieren des Attributsnode.default verwendet haben, beim späteren Zugriff auf den Wert jedochnode verwendet haben direkt. Die Verwendung vonnode.defaultdefiniert, dass wir ein Attribut vom Typdefault erstellen. Der Wert dieses Attributs kann durch einen anderen Typ mit höherer Priorität überschrieben werden, z. B. durch die Attributenormal oderoverride.

Die Priorität der Attribute kann zunächst etwas verwirrend sein, aber Sie werden sich nach einiger Übung daran gewöhnen. Betrachten Sie das folgende Beispiel, um das Verhalten zu veranschaulichen:

node.normal['main']['package']  = "vim"

node.override['main']['package'] = "git"

node.default['main']['package'] = "curl"

apt_package node['main']['package'] do
 action :install
end

Wissen Sie, welches Paket in diesem Fall installiert wird? Wenn Siegit erraten haben, haben Sie richtig geraten. Unabhängig von der Reihenfolge, in der die Attribute definiert wurden, ergibt die höhere Priorität des Typsoverride die+node['main']['package'] be evaluated to+`git.

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.

Chef unterstützt alle Ruby-Loop-Strukturen zum Erstellen von Loops innerhalb von Rezepten. Für die einfache Verwendung isteach eine häufige Wahl:

['vim', 'git', 'curl'].each do |package|
 apt_package package do
   action :install
 end
end

Anstatt ein Inline-Array zu verwenden, können Sie auch eine Variable oder ein Attribut zum Definieren der Parameter erstellen, die Sie in der Schleife verwenden möchten. So bleiben die Dinge übersichtlicher und übersichtlicher. Unten dasselbe Beispiel, in dem jetzt eine lokale Variable zum Definieren der zu installierenden Pakete verwendet wird:

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

packages.each do |package|
 apt_package package do
   action :install
 end
end

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.

Chef unterstützt alle Ruby-Bedingungen, um bedingte Anweisungen in Rezepten zu erstellen. Darüber hinaus unterstützen alle Ressourcentypen zwei spezielle Eigenschaften, die einen Ausdruck auswerten, bevor entschieden wird, ob die Aufgabe ausgeführt werden soll oder nicht:if_only undnot_if.

Im folgenden Beispiel wird geprüft, obphp vorhanden ist, bevor versucht wird, die Erweiterungphp-pear zu installieren. Mit dem Befehlwhich wird überprüft, ob auf diesem System derzeit eine ausführbare Dateiphp installiert ist. Wenn der Befehlwhich php false zurückgibt, wird diese Aufgabe nicht ausgeführt:

apt_package "php-pear" do
 action :install
 only_if "which php"
end

Wenn wir das Gegenteil tun möchten und jederzeit einen Befehlexcept ausführen, wenn eine Bedingung als wahr bewertet wird, verwenden wir stattdessennot_if. In diesem Beispiel wirdphp5 installiert, es sei denn, das System ist CentOS:

apt_package "php5" do
 action :install
 not_if { node['platform'] == 'centos' }
end

Wenn Sie komplexere Auswertungen durchführen und mehrere Aufgaben unter einer bestimmten Bedingung ausführen möchten, können Sie eine der Standard-Ruby-Bedingungen verwenden. Das folgende Beispiel führtapt-get update nur aus, wenn das System entweder Debianor Ubuntu ist:

if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
 execute "apt-get update" do
   command "apt-get update"
 end
end

Das Attributnode['platform'] ist ein automatisches Attribut von Chef. Das letzte Beispiel diente nur dazu, eine komplexere bedingte Konstruktion zu demonstrieren. Sie konnte jedoch durch einen einfachen Test mit dem automatischen Attributnode['platform_family'] ersetzt werden, das sowohl für Debian- als auch für Ubuntu-Systeme "debian" zurückgibt.

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.

Chef verwendet Embedded Ruby (ERB) -Vorlagen, die dem von Puppet verwendeten Format entsprechen. Sie unterstützen Bedingungen, Schleifen und andere Ruby-Funktionen.

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


    ServerAdmin webmaster@localhost
    DocumentRoot <%= @doc_root %>

    >
        AllowOverride All
        Require all granted
    

Um die Vorlage anzuwenden, müssen wir einetemplate-Ressource erstellen. So würden Sie diese Vorlage anwenden, um den virtuellen Apache-Standardhost zu ersetzen:

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
end

Chefkoch trifft einige Annahmen beim Umgang mit lokalen Dateien, um die Organisation und Modularität durchzusetzen. In diesem Fall sucht Chefkoch nach einer Vorlagendatei fürvhost.erbin einem Ordner fürtemplates, der sich in demselben Kochbuch befinden sollte, in dem sich dieses Rezept befindet.

Im Gegensatz zu den anderen Konfigurationsverwaltungstools, die wir bisher gesehen haben, hat Chef einen strengeren Bereich für Variablen. Dies bedeutet, dass Sie alle Variablen, die Sie in einer Vorlage verwenden möchten, explizit angeben müssen, wenn Sie die Ressourcetemplatedefinieren. In diesem Beispiel haben wir die Methodevariables verwendet, um das Attributdoc_root weiterzugeben, das wir in der Vorlage für den virtuellen Host benötigen.

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.

In Chef müssen Serviceressourcen deklariert werden, bevor Sie versuchen, sie zu benachrichtigen. Andernfalls wird eine Fehlermeldung angezeigt.

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 einem virtuellen Hostwechsel neu gestartet wird, müssen Sie zuerst eineservice-Ressource für den Apache-Dienst erstellen. So wird eine solche Ressource in Chef definiert:

service "apache2" do
  action [ :enable, :start ]
end

Wenn Sie nun die Ressourcetemplatedefinieren, müssen Sie eine Optionnotifyeinschließen, um einen Neustart auszulösen:

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end

Beispielrezept

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 HTML-Datei, die vom Webserver bereitgestellt werden soll, finden Sie inon Github. Der Ordner enthält auch eine Vagrant-Datei, mit der Sie das Manifest in einem vereinfachten Setup mit einer vonVagrant verwalteten virtuellen Maschine testen können.

Nachfolgend finden Sie das komplette Rezept:

node.default['main']['doc_root'] = "/vagrant/web"

execute "apt-get update" do
 command "apt-get update"
end

apt_package "apache2" do
 action :install
end

service "apache2" do
 action [ :enable, :start ]
end

directory node['main']['doc_root'] do
 owner 'www-data'
 group 'www-data'
 mode '0644'
 action :create
end

cookbook_file "#{node['main']['doc_root']}/index.html" do
 source 'index.html'
 owner 'www-data'
 group 'www-data'
 action :create
end

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end

Rezept erklärt

Linie 1

Das Rezept beginnt mit einer Definition vonattribute,node['main']['doc_root']. Wir hätten hier eine einfache lokale Variable verwenden können. In den meisten Anwendungsfällen müssen Rezepte jedoch globale Variablen definieren, die aus enthaltenen Rezepten oder anderen Dateien verwendet werden. In diesen Situationen ist es erforderlich, anstelle einer lokalen Variablen ein Attribut zu erstellen, da letztere einen begrenzten Bereich hat.

Zeilen 3-5

Dieseexecute-Ressource führtapt-get update aus.

Zeilen 7-10

Dieseapt_package-Ressource installiert das Paketapache2.

Zeilen 12-15

Dieseservice-Ressource aktiviert und startet den Dienstapache2. Später müssen wir diese Ressource für einen Neustart des Dienstes benachrichtigen. Es ist wichtig, dass die Service-Definition vor jeder Ressource steht, die versucht, einen Service zu benachrichtigen. Andernfalls wird ein Fehler angezeigt.

Zeilen 17-22

Diesedirectory-Ressource verwendet den durch das benutzerdefinierte Attributnode['main']['doc_root'] definierten Wert, um ein Verzeichnis zu erstellen, das alsdocument root dient.

Zeilen 24-29

Die Ressourcecookbook_filewird verwendet, um eine lokale Datei auf einen Remote-Server zu kopieren. Diese Ressource kopiert dieindex.html-Datei und legt sie im Dokumentstamm ab, den wir in einer vorherigen Aufgabe erstellt haben.

Zeilen 31-36

Schließlich wendet diesetemplate-Ressource unsere virtuelle Apache-Hostvorlage an und benachrichtigt den Dienstapache2 für einen Neustart.

Fazit

Chef ist ein leistungsstarkes Konfigurationsmanagement-Tool, das die Ruby-Sprache nutzt, um die Serverbereitstellung und -bereitstellung zu automatisieren. Es gibt Ihnen die Freiheit, die Standardsprachfunktionen für maximale Flexibilität zu verwenden und für einige Ressourcen benutzerdefinierte DSLs anzubieten.