Konfigurationsmanagement 101: Ansible-Playbooks schreiben

Einführung

Zusammengefasst ist die Serverkonfigurationsverwaltung (auch als IT-Automatisierung bezeichnet) eine Lösung, um Ihre Infrastrukturverwaltung in eine Codebasis umzuwandeln, die alle für die Bereitstellung eines Servers erforderlichen Prozesse beschreibt. Diese werden in einer Reihe von Bereitstellungsskripten dargestellt, die versioniert und leicht wiederverwendet werden können. Sie kann die Integrität jeder Serverinfrastruktur im Laufe der Zeit erheblich verbessern.

In einem vorherigen Leitfaden haben wir über die Hauptvorteile der Implementierung einer Konfigurationsverwaltungsstrategie für Ihre Serverinfrastruktur gesprochen, wie Konfigurationsverwaltungstools funktionieren und welche Funktionen diese Tools typischerweise gemeinsam haben.

In diesem Teil der Serie werden wir Sie durch den Prozess der Automatisierung der Serverbereitstellung mithilfe von Ansible führen, einem Konfigurationsverwaltungstool, das einen vollständigen Automatisierungsrahmen und Orchestrierungsfähigkeiten bietet, während es das Ziel ultimativer Einfachheit und Minimalismus beibehält. Wir werden uns auf die Sprachterminologie, Syntax und Funktionen konzentrieren, die für die Erstellung eines vereinfachten Beispiels zur vollständigen Automatisierung der Bereitstellung eines Ubuntu 18.04-Web-Servers mit Apache erforderlich sind.

Die folgende Liste enthält alle Schritte, die wir automatisieren müssen, um unser Ziel zu erreichen:

  1. Das apt-Cache aktualisieren
  2. Apache installieren
  3. Einen benutzerdefinierten Dokumentstammverzeichnis erstellen
  4. Platzieren Sie eine index.html-Datei im benutzerdefinierten Dokumentenstamm
  5. Wenden Sie eine Vorlage an, um unseren benutzerdefinierten virtuellen Host einzurichten
  6. Starten Sie Apache neu

Zuerst werfen wir einen Blick auf die von Ansible verwendete Terminologie, gefolgt von einer Übersicht über die Hauptfunktionen der Sprache, die zum Schreiben von Playbooks verwendet werden können. Am Ende des Leitfadens finden Sie den Inhalt eines vollständigen Bereitstellungsbeispiels, um die beschriebenen Schritte zur Einrichtung von Apache unter Ubuntu 18.04 zu automatisieren.

Hinweis: Dieser Leitfaden soll Sie mit der Ansible-Sprache vertraut machen und Ihnen zeigen, wie Sie Playbooks schreiben können, um Ihre Serverbereitstellung zu automatisieren. Für einen einführenderen Blick auf Ansible, einschließlich der Schritte, die für die Installation und den Einstieg in dieses Tool erforderlich sind, sowie Informationen zum Ausführen von Ansible-Befehlen und Playbooks, lesen Sie unseren Leitfaden „Wie man Ansible unter Ubuntu 18.04 installiert und konfiguriert“.

Erste Schritte

Bevor wir uns einen praxisnäheren Blick auf Ansible werfen können, ist es wichtig, dass wir uns mit wichtigen Terminologie und Konzepten vertraut machen, die von diesem Tool eingeführt wurden.

Terminologie

Die folgende Liste enthält einen schnellen Überblick über die wichtigsten Begriffe, die von Ansible verwendet werden:

  • Control Node: Die Maschine, auf der Ansible installiert ist und die für die Ausführung der Bereitstellung auf den von Ihnen verwalteten Servern verantwortlich ist.
  • Inventar: Eine INI-Datei, die Informationen über die von Ihnen verwalteten Server enthält.
  • Playbook: Eine YAML-Datei, die eine Reihe von Verfahren enthält, die automatisiert werden sollen.
  • Aufgabe: Ein Block, der ein einzelnes Verfahren definiert, das ausgeführt werden soll, z. B.: Installation eines Pakets.
  • Modul: Ein Modul abstrahiert typischerweise eine Systemaufgabe, wie den Umgang mit Paketen oder das Erstellen und Ändern von Dateien. Ansible verfügt über eine Vielzahl von integrierten Modulen, aber Sie können auch benutzerdefinierte erstellen.
  • Rolle: Ein Satz von verwandten Playbooks, Vorlagen und anderen Dateien, die in einer vordefinierten Weise organisiert sind, um die Wiederverwendung und Weitergabe zu erleichtern.
  • Play: Eine Bereitstellung, die von Anfang bis Ende ausgeführt wird, wird als Spiel bezeichnet.
  • Fakten: Globale Variablen, die Informationen über das System enthalten, wie Netzwerkschnittstellen oder Betriebssystem.
  • Handler: Werden verwendet, um Änderungen am Servicestatus auszulösen, wie das Neustarten oder Neu laden eines Dienstes.

Aufgabenformat

A task defines a single automated step that should be executed by Ansible. It typically involves the usage of a module or the execution of a raw command. This is how a task looks:

- name: This is a task
  apt: name=vim state=latest

Der name-Teil ist eigentlich optional, aber empfohlen, da er im Ausgabebereich der Bereitstellung angezeigt wird, wenn die Aufgabe ausgeführt wird. Der apt-Teil ist ein integriertes Ansible-Modul, das das Management von Paketen auf Debian-basierten Distributionen abstrahiert. Diese Beispiel-Aufgabe teilt Ansible mit, dass das Paket vim seinen Zustand auf latest geändert haben soll, was dazu führt, dass der Paketmanager dieses Paket installiert, falls es noch nicht installiert ist.

Playbook-Format

Playbooks sind YAML-Dateien, die eine Reihe von Anweisungen zur Automatisierung der Bereitstellung eines Servers enthalten. Das folgende Beispiel ist ein einfaches Playbook, das zwei Aufgaben ausführt: Es aktualisiert den apt-Cache und installiert anschließend vim:

---
- hosts: all
  become: true
  tasks:
     - name: Update apt-cache 
       apt: update_cache=yes

     - name: Install Vim
       apt: name=vim state=latest

YAML verwendet Einrückungen, um Datenstrukturen zu serialisieren. Aus diesem Grund müssen Sie beim Schreiben von Playbooks und insbesondere beim Kopieren von Beispielen besonders darauf achten, die richtige Einrückung beizubehalten.

Bevor wir das Ende dieses Leitfadens erreichen, werden wir ein praxisnäheres Beispiel für ein Playbook sehen, das ausführlich erklärt wird. Der nächste Abschnitt gibt einen Überblick über die wichtigsten Elemente und Funktionen, die zum Schreiben von Ansible-Playbooks verwendet werden können.

Das Schreiben von Playbooks

Nun, da Sie mit den grundlegenden Terminologien und dem allgemeinen Format von Playbooks und Aufgaben in Ansible vertraut sind, werden wir einige Funktionen von Playbooks kennenlernen, die uns dabei helfen können, vielseitigere Automatisierungen zu erstellen.

Arbeiten mit Variablen

Es gibt verschiedene Möglichkeiten, Variablen in Ansible zu definieren. Der einfachste Weg besteht darin, den vars-Abschnitt eines Playbooks zu verwenden. Das folgende Beispiel definiert eine Variable package, die später innerhalb einer Aufgabe verwendet wird:

---
- hosts: all
  become: true
  vars:
     package: vim
  tasks:
     - name: Install Package
       apt: name={{ package }} state=latest

Die Variable package hat einen globalen Gültigkeitsbereich, was bedeutet, dass sie von jedem Punkt der Bereitstellung aus abgerufen werden kann, auch von eingebundenen Dateien und Vorlagen.

Verwendung von Schleifen

Schleifen werden typischerweise verwendet, um eine Aufgabe mit verschiedenen Eingabewerten zu wiederholen. Anstatt beispielsweise 10 Aufgaben zum Installieren 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.

Um eine Schleife innerhalb einer Aufgabe zu erstellen, fügen Sie die Option with_items mit einem Array von Werten hinzu. Der Inhalt kann über die Schleifenvariable item abgerufen werden, wie im folgenden Beispiel gezeigt:

- name: Install Packages
  apt: name={{ item }} state=latest
  with_items:
     - vim
     - git
     - curl  

Sie können auch eine Array-Variable verwenden, um Ihre Elemente zu definieren:

---
- hosts: all
  become: true
  vars:
     packages: [ 'vim', 'git', 'curl' ]
  tasks:
     - name: Install Package
       apt: name={{ item }} state=latest
       with_items: "{{ packages }}"

Verwendung von Bedingungen

Bedingungen können verwendet werden, um dynamisch zu entscheiden, ob eine Aufgabe ausgeführt werden soll oder nicht, basierend auf einer Variablen oder einer Ausgabe aus einem Befehl, zum Beispiel.

Das folgende Beispiel wird nur Debian-basierte Systeme herunterfahren:

- name: Shutdown Debian Based Systems
  command: /sbin/shutdown -t now
  when: ansible_os_family == "Debian"

Die Bedingung when erhält als Argument einen Ausdruck, der ausgewertet werden soll. Die Aufgabe wird nur ausgeführt, wenn der Ausdruck als true ausgewertet wird. In unserem Beispiel haben wir eine Tatsache getestet, um zu überprüfen, ob das Betriebssystem aus der Debian-Familie stammt.

A common use case for conditionals in IT automation is when the execution of a task depends on the output of a command. With Ansible, the way we implement this is by registering a variable to hold the results of a command execution, and then testing this variable in a subsequent task. We can test for the command’s exit status (if failed or successful). We can also check for specific contents inside the output, although this might require the usage of regex expressions and string parsing commands.

Im nächsten Beispiel werden zwei bedingte Aufgaben basierend auf der Ausgabe eines php -v-Befehls gezeigt. Wir werden den Exit-Status des Befehls testen, da wir wissen, dass er fehlschlagen wird, wenn PHP nicht auf diesem Server installiert ist. Der Teil ignore_errors der Aufgabe ist wichtig, um sicherzustellen, dass die Bereitstellung fortgesetzt wird, auch wenn der Befehl nicht erfolgreich ausgeführt wird.

- name: Check if PHP is installed
  register: php_installed
  command: php -v
  ignore_errors: true

- name: This task is only executed if PHP is installed
  debug: var=php_install
  when: php_installed|success
  
- name: This task is only executed if PHP is NOT installed
  debug: msg='PHP is NOT installed'
  when: php_installed|failed

Das hier verwendete debug-Modul ist ein nützliches Modul zum Anzeigen von Inhalten von Variablen oder Debug-Nachrichten. Es kann entweder einen String ausgeben (wenn das msg-Argument verwendet wird) oder den Inhalt einer Variablen ausgeben (wenn das var-Argument verwendet wird).

Arbeiten mit Vorlagen

Vorlagen werden typischerweise verwendet, um Konfigurationsdateien einzurichten, die die Verwendung von Variablen und anderen Funktionen ermöglichen, um diese Dateien vielseitiger und wiederverwendbarer zu machen. Ansible verwendet den Jinja2-Vorlagenmotor.

Das folgende Beispiel ist eine Vorlage zur Einrichtung eines Apache-Virtualhosts, wobei eine Variable für die Einrichtung des Dokumentroots für diesen Host verwendet wird:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot {{ doc_root }}

    <Directory {{ doc_root }}>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Das integrierte Modul template wird verwendet, um die Vorlage aus einer Aufgabe anzuwenden. Wenn Sie die oben genannte Vorlagendatei vhost.tpl benannt und sie im selben Verzeichnis wie Ihr Playbook platziert haben, ist dies, wie Sie die Vorlage anwenden würden, um den Standard-Apache-Virtualhost zu ersetzen:

- name: Change default Apache virtual host
  template: 
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf

Definition und Auslösung von Handlern

Handler werden verwendet, um einen Zustandswechsel in einem Dienst auszulösen, wie z.B. ein Neustart oder ein Stoppen. Obwohl sie ähnlich wie normale Aufgaben aussehen mögen, werden Handler nur ausgeführt, wenn sie zuvor durch eine notify-Anweisung in einer Aufgabe ausgelöst wurden. Sie werden typischerweise als Array in einem handlers-Abschnitt des Playbooks definiert, können aber auch in separaten Dateien stehen.

Lassen Sie uns unser vorheriges Beispiel für die Verwendung von Vorlagen betrachten, bei dem wir einen Apache-Virtualhost einrichten. Wenn Sie sicherstellen möchten, dass Apache nach einer Änderung am Virtualhost neu gestartet wird, müssen Sie zunächst einen Handler für den Apache-Dienst erstellen. So werden Handler innerhalb eines Playbooks definiert:

handlers:
    - name: restart apache
      service: name=apache2 state=restarted
    
    - name: other handler
      service: name=other state=restarted

Die name-Direktive hier ist wichtig, weil sie der eindeutige Bezeichner dieses Handlers sein wird. Um diesen Handler von einer Aufgabe aus zu aktivieren, sollten Sie die notify-Option verwenden:

- name: Change default Apache virtual host
  template: 
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf
  notify: restart apache

Wir haben einige der wichtigsten Funktionen gesehen, die Sie verwenden können, um mit dem Schreiben von Ansible-Playbooks zu beginnen. Im nächsten Abschnitt werden wir uns ein praxisnäheres Beispiel eines Playbooks ansehen, das die Installation und Konfiguration von Apache auf Ubuntu automatisieren wird.

Beispiel-Playbook

Werfen wir nun einen Blick auf ein Playbook, das die Installation eines Apache-Web-Servers auf einem Ubuntu 18.04-System automatisiert, wie in der Einführung zu diesem Leitfaden besprochen.

Das vollständige Beispiel, einschließlich der Vorlagendatei zum Einrichten von Apache und einer HTML-Datei, die vom Webserver bereitgestellt werden soll, finden Sie auf Github. Der Ordner enthält auch eine Vagrantfile, mit der Sie das Playbook in einem vereinfachten Setup testen können, das eine virtuelle Maschine verwendet, die von Vagrant verwaltet wird.

Inhalte des Playbooks

Der vollständige Inhalt des Playbooks steht hier zur Verfügung, um ihn bequem durchzusehen:

playbook.yml
  1. ---
  2. - hosts: all
  3. become: true
  4. vars:
  5. doc_root: /var/www/example
  6. tasks:
  7. - name: Update apt
  8. apt: update_cache=yes
  9. - name: Install Apache
  10. apt: name=apache2 state=latest
  11. - name: Create custom document root
  12. file: path={{ doc_root }} state=directory owner=www-data group=www-data
  13. - name: Set up HTML file
  14. copy: src=index.html dest={{ doc_root }}/index.html owner=www-data group=www-data mode=0644
  15. - name: Set up Apache virtual host file
  16. template: src=vhost.tpl dest=/etc/apache2/sites-available/000-default.conf
  17. notify: restart apache
  18. handlers:
  19. - name: restart apache
  20. service: name=apache2 state=restarted

Lassen Sie uns jeden Abschnitt dieses Playbooks genauer untersuchen:

hosts: all
Das Playbook beginnt damit zu erklären, dass es auf alle Hosts in Ihrem Inventar angewendet werden sollte (hosts: all). Es ist möglich, die Ausführung des Playbooks auf einen bestimmten Host oder eine Gruppe von Hosts zu beschränken. Diese Option kann zur Ausführungszeit überschrieben werden.

become: true
Der Teil become: true fordert Ansible auf, bei der Ausführung aller Aufgaben in diesem Playbook eine Privilegien-Eskalation (sudo) zu verwenden. Diese Option kann auf Task-Ebene überschrieben werden.

vars
Definiert eine Variable, doc_root, die später in einer Aufgabe verwendet wird. Dieser Abschnitt kann mehrere Variablen enthalten.

tasks
Der Abschnitt, in dem die tatsächlichen Aufgaben definiert sind. Die erste Aufgabe aktualisiert den apt-Cache, und die zweite Aufgabe installiert das Paket apache2.

Die dritte Aufgabe verwendet das integrierte Modul file, um ein Verzeichnis zu erstellen, das als unser Dokumentenstamm dienen soll. Mit diesem Modul können Dateien und Verzeichnisse verwaltet werden.

Die vierte Aufgabe verwendet das Modul copy, um eine lokale Datei auf den Remote-Server zu kopieren. Wir kopieren eine einfache HTML-Datei, die als unsere von Apache gehostete Website dienen soll.

handlers
Schließlich haben wir den Abschnitt handlers, in dem die Services deklariert sind. Wir definieren den Handler restart apache, der von der vierten Aufgabe benachrichtigt wird, in der die Apache-Vorlage angewendet wird.

Ausführen eines Playbooks

Nachdem Sie den Inhalt dieses Playbooks auf Ihren Ansible-Steuerknoten heruntergeladen haben, können Sie ansible-playbook verwenden, um es auf einem oder mehreren Knoten aus Ihrem Inventar auszuführen. Der folgende Befehl führt das Playbook auf allen Hosts aus Ihrer Standardinventardatei aus und verwendet die SSH-Schlüsselpaar-Authentifizierung, um sich als aktueller Systembenutzer zu verbinden:

  1. ansible-playbook playbook.yml

Sie können auch -l verwenden, um die Ausführung auf einen einzelnen Host oder eine Gruppe von Hosts aus Ihrem Inventar zu beschränken:

  1. ansible-playbook -l host_or_group playbook.yml

Wenn Sie einen anderen SSH-Benutzer angeben müssen, um sich mit dem Remote-Server zu verbinden, können Sie das Argument -u Benutzer zu diesem Befehl hinzufügen:

  1. ansible-playbook -l host_or_group playbook.yml -u remote-user

Weitere Informationen zum Ausführen von Ansible-Befehlen und Playbooks finden Sie in unserem Leitfaden „Wie man Ansible unter Ubuntu 18.04 installiert und konfiguriert“.

Zusammenfassung

Ansible ist ein minimalistisches IT-Automatisierungstool mit einer geringen Lernkurve, das YAML für seine Bereitstellungsskripte verwendet. Es verfügt über eine Vielzahl von integrierten Modulen, die verwendet werden können, um Aufgaben wie die Installation von Paketen und die Arbeit mit Vorlagen abstrakt darzustellen. Seine vereinfachten Infrastrukturanforderungen und die einfache Sprache können gut für diejenigen geeignet sein, die mit der Konfigurationsverwaltung beginnen. Es könnte jedoch einige fortgeschrittene Funktionen fehlen, die Sie bei komplexeren Tools wie Puppet und Chef finden können.

In dem nächsten Teil dieser Serie werden wir einen praktischen Überblick über Puppet sehen, ein beliebtes und etabliertes Konfigurationsverwaltungstool, das eine ausdrucksstarke und leistungsstarke benutzerdefinierte DSL auf Ruby-Basis verwendet, um Bereitstellungsskripte zu schreiben.

Source:
https://www.digitalocean.com/community/tutorials/configuration-management-101-writing-ansible-playbooks