35 Erweiterte Playbook-Techniken

Während einfache Playbooks aus einer Liste von Tasks bestehen, die auf einer Gruppe von Hosts ausgeführt werden, bieten erweiterte Playbook-Techniken zusätzliche Flexibilität, Skalierbarkeit und Wiederverwendbarkeit. Durch den Einsatz von Techniken wie bedingter Logik, Schleifen, Blockstrukturen und der dynamischen Modifizierung von Playbooks können komplexe Automatisierungsszenarien effizient bewältigt werden.

35.1 Playbook-Blöcke und Bedingte Logik

35.1.1 Verwendung von Blöcken (block, rescue, always)

Blöcke in Ansible dienen dazu, mehrere Aufgaben zusammenzufassen, und erlauben es, Fehlerbehandlungen (rescue) und immer auszuführende Aufgaben (always) zu definieren. Sie ermöglichen eine bessere Kontrolle über die Ausführung von Aufgaben und tragen zur Fehlerbehebung bei.

Beispiel für einen Block mit Fehlerbehandlung:

- name: Installation eines Webservers
  block:
    - name: Installiere Apache
      apt:
        name: apache2
        state: present
      notify: Starte Apache

    - name: Konfiguriere Apache
      template:
        src: apache.conf.j2
        dest: /etc/apache2/apache2.conf

  rescue:
    - name: Benachrichtige bei Fehlern
      debug:
        msg: "Fehler bei der Installation oder Konfiguration von Apache."

  always:
    - name: Stelle sicher, dass Apache-Protokolle vorhanden sind
      file:
        path: /var/log/apache2
        state: directory

35.1.2 Bedingte Logik (when)

Mit der when-Anweisung können Sie Playbooks so steuern, dass Tasks nur dann ausgeführt werden, wenn bestimmte Bedingungen erfüllt sind. Dies kann auf Fakten, Variablen oder andere Bedingungen basieren.

Beispiel für bedingte Logik:

- name: Installiere Apache nur auf Debian-basierten Systemen
  apt:
    name: apache2
    state: present
  when: ansible_os_family == "Debian"

Sie können komplexere Bedingungen mit and, or und not kombinieren.

Beispiel für eine kombinierte Bedingung:

- name: Installiere Nginx nur auf Debian-basierten Systemen, außer wenn Apache läuft
  apt:
    name: nginx
    state: present
  when: ansible_os_family == "Debian" and apache_running == false

35.2 Verwendung von Schleifen und dynamischen Aufgaben

35.2.1 Schleifen mit loop

Schleifen (loop) in Ansible ermöglichen die Wiederholung einer Aufgabe für eine Liste von Elementen. Dies kann die Installation mehrerer Pakete, die Verwaltung mehrerer Benutzer oder das Bearbeiten von Konfigurationsdateien umfassen.

Beispiel für die Installation mehrerer Pakete:

- name: Installiere mehrere Pakete
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - apache2
    - mysql-server
    - php

35.2.2 Geschachtelte Schleifen

Sie können geschachtelte Schleifen verwenden, um mehrere Variablen oder komplexe Datenstrukturen in Playbooks zu verwalten.

Beispiel für eine geschachtelte Schleife:

- name: Erstelle Verzeichnisse für verschiedene Benutzer
  file:
    path: "/home/{{ item.user }}/{{ item.folder }}"
    state: directory
  loop:
    - { user: 'alice', folder: 'documents' }
    - { user: 'bob', folder: 'music' }
    - { user: 'charlie', folder: 'pictures' }

35.2.3 Dynamische Aufgaben mit include_tasks und import_tasks

Mit include_tasks und import_tasks können Sie dynamisch Aufgaben in ein Playbook einbinden. Der Unterschied besteht darin, dass include_tasks die Aufgaben zur Laufzeit einbindet, während import_tasks dies zur Parsing-Zeit tut.

Beispiel für die dynamische Einbindung von Tasks:

- name: Importiere ein statisches Task-Set
  import_tasks: tasks/apache.yml

- name: Inkludiere ein dynamisches Task-Set
  include_tasks: tasks/dynamic_tasks.yml
  when: ansible_os_family == "RedHat"

35.3 Variablen, Templates und Jinja2

35.3.1 Verwendung von Templates und Jinja2

Ansible verwendet Jinja2-Templates, um dynamische Konfigurationsdateien zu erstellen, die während der Playbook-Ausführung angepasst werden können. Dies ermöglicht eine flexible und wiederverwendbare Verwaltung von Konfigurationsdateien.

Beispiel für ein Jinja2-Template (nginx.conf.j2):

server {
    listen 80;
    server_name {{ server_name }};

    location / {
        root {{ document_root }};
    }
}

Beispiel für die Verwendung des Templates in einem Playbook:

- name: Wende Nginx-Template an
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  vars:
    server_name: example.com
    document_root: /var/www/html

35.3.2 Filter und Jinja2-Funktionen

Mit Jinja2-Filtern können Sie Variablen transformieren und Daten innerhalb eines Playbooks dynamisch verarbeiten.

Beispiel für die Verwendung von Filtern:

- name: Zeige die erste IP-Adresse
  debug:
    msg: "Die erste IP-Adresse ist {{ ansible_all_ipv4_addresses | first }}"

- name: Zeige eine Liste von Benutzern in Großbuchstaben an
  debug:
    msg: "{{ item | upper }}"
  loop:
    - alice
    - bob
    - charlie

35.3.3 Komplexe Datenstrukturen und Dictionaries

In Ansible können Sie komplexe Datenstrukturen wie Listen und Dictionaries verwenden, um mehrere Werte zu speichern und darauf dynamisch zuzugreifen.

Beispiel für ein Dictionary:

users:
  alice:
    shell: /bin/bash
    uid: 1001
  bob:
    shell: /bin/zsh
    uid: 1002

In einem Playbook können Sie diese Datenstruktur durchlaufen:

- name: Erstelle Benutzer
  user:
    name: "{{ item.key }}"
    shell: "{{ item.value.shell }}"
    uid: "{{ item.value.uid }}"
  loop: "{{ users | dict2items }}"

35.4 Fehlerbehandlung und Wiederholungen

35.4.1 Wiederholungen mit retry

Manchmal müssen Aufgaben wiederholt werden, wenn sie beim ersten Versuch fehlschlagen, z.B. aufgrund vorübergehender Netzwerkprobleme. Mit retry und delay können Sie dies steuern.

Beispiel für eine wiederholte Aufgabe:

- name: Prüfe, ob der Webserver verfügbar ist
  uri:
    url: http://localhost
    return_content: yes
  retries: 5
  delay: 10
  until: result.status == 200
  register: result

35.4.2 Fehlerbehandlung mit failed_when und ignore_errors

Mit failed_when können Sie benutzerdefinierte Bedingungen festlegen, unter denen eine Aufgabe als fehlgeschlagen betrachtet wird. Mit ignore_errors können Sie Fehler ignorieren und das Playbook fortsetzen.

Beispiel für benutzerdefinierte Fehlerbedingungen:

- name: Überprüfe den freien Speicherplatz
  command: df -h /
  register: disk_usage
  failed_when: "'100%' in disk_usage.stdout"

Beispiel für das Ignorieren von Fehlern:

- name: Starte einen Dienst, aber ignoriere Fehler
  service:
    name: apache2
    state: restarted
  ignore_errors: yes