27 Variablen in Playbooks

27.1 Einführung: Warum Variablen?

Angenommen, Sie müssen denselben Webserver auf zehn verschiedenen Systemen installieren, aber mit jeweils unterschiedlichen Ports, Logverzeichnissen und Konfigurationen. Statt zehn separate Playbooks zu schreiben und zu warten, nutzen Sie Variablen – und haben damit nur ein einziges, flexibles Playbook für alle Umgebungen.

27.2 Definition und Verwendung von Variablen in Playbooks

Variablen sind ein wesentliches Element in Ansible, das die Flexibilität und Wiederverwendbarkeit von Playbooks erheblich steigert. Durch den Einsatz von Variablen können Sie Werte dynamisch definieren und anpassen, ohne die Struktur des Playbooks ändern zu müssen. Variablen ermöglichen es, Playbooks für verschiedene Umgebungen oder Hostgruppen zu verwenden, indem spezifische Werte einfach angepasst werden.

27.2.1 Deklaration von Variablen

Variablen können an verschiedenen Stellen in Ansible definiert werden, darunter:

  1. In Playbooks direkt: Variablen können direkt im Playbook unter dem Schlüsselwort vars definiert werden.
  2. In group_vars und host_vars: Variablen können in Dateien definiert werden, die spezifisch für Gruppen oder Hosts sind.
  3. In Inventories: Variablen können auch direkt im Inventory definiert werden.
  4. In der Kommandozeile: Variablen können beim Ausführen von Playbooks über die Kommandozeile übergeben werden.
  5. In Rollen: Variablen können in Rollen definiert werden, was eine wiederverwendbare Struktur ermöglicht.

Beispiel für die Deklaration von Variablen in einem Playbook:

---
- name: Beispiel Playbook mit Variablen
  hosts: webservers
  vars:
    http_port: 8080
    max_clients: 100

  tasks:
    - name: Setze Apache Port
      lineinfile:
        path: /etc/apache2/ports.conf
        regexp: '^Listen'
        line: "Listen {{ http_port }}"

    - name: Setze maximale Anzahl von Clients
      lineinfile:
        path: /etc/apache2/apache2.conf
        regexp: '^MaxClients'
        line: "MaxClients {{ max_clients }}"

27.2.2 Zugriff auf Variablen

Variablen werden in Ansible durch doppelgeschweifte Klammern {{ }} referenziert. Ansible löst diese Platzhalter zur Laufzeit auf und ersetzt sie durch die tatsächlichen Werte der Variablen.

Beispiel:

line: "Listen {{ http_port }}"

In diesem Beispiel wird die Variable http_port aufgelöst und der Wert, z.B. 8080, wird in die Konfigurationsdatei eingefügt.

27.3 Variablen-Scope und -Priorität

In Ansible gibt es eine festgelegte Reihenfolge, nach der Variablen priorisiert und überschrieben werden können. Diese Prioritätenreihenfolge, auch als “Precedence” bezeichnet, bestimmt, welche Variable verwendet wird, wenn mehrere Variablen mit demselben Namen definiert sind.

Wichtiger Hinweis: Bei gleichnamigen Variablen wird immer der Wert mit der höchsten Priorität verwendet. Dies kann zu schwer nachvollziehbaren Fehlern führen, wenn Variablen in mehreren Quellen definiert sind.

27.3.1 Reihenfolge der Variablen-Priorität:

Rang Quelle Gültigkeitsbereich Überschreibbar
1 Kommandozeile (-e) global ja
2 Playbook-vars: pro Playbook ja
3 Rollen-vars/main.yml Rolle ja
4 group_vars / host_vars Inventory-spezifisch ja
5 Rollen-defaults/main.yml Rolle (Standardwert) ja
6 set_fact zur Laufzeit Host-lokal ja
7 automatisch gesammelte Fakten Host-lokal (read-only) nein

27.3.2 Praktische Anwendung der Prioritäten

Beispiel zur Demonstration der Prioritäten:

---
- name: Beispiel Playbook für Variablen-Priorität
  hosts: webservers
  vars:
    http_port: 8080  # Wird überschrieben, wenn über Kommandozeile definiert
    max_clients: 100

  tasks:
    - name: Setze Apache Port
      lineinfile:
        path: /etc/apache2/ports.conf
        regexp: '^Listen'
        line: "Listen {{ http_port }}"

Wird dieses Playbook mit einer über die Kommandozeile definierten Variable aufgerufen, hat diese den Vorrang:

ansible-playbook -i inventory playbook.yml -e "http_port=9090"

In diesem Fall wird http_port mit 9090 überschrieben.

27.3.2.1 Trennung nach Scope-Bereichen

Rolleninterner Scope:

Externer Scope:

27.4 Platzhalter und Variablen-Interpolation

Ansible ermöglicht es, Variablen innerhalb von Strings zu interpolieren, was bedeutet, dass Variablenwerte in Strings eingefügt werden können, um dynamische Werte zu erzeugen.

27.4.1 Beispiel für einfache Variablen-Interpolation:

Playbook-Ausschnitt:

- name: Erstelle eine Begrüßungsdatei
  copy:
    content: "Willkommen, {{ ansible_user }}!"
    dest: /home/{{ ansible_user }}/welcome.txt

In diesem Beispiel wird der Benutzername, der zur Laufzeit durch ansible_user bestimmt wird, sowohl im Inhalt als auch im Dateipfad verwendet.

27.4.2 Verschachtelte Variablen und komplexe Strukturen

Ansible unterstützt auch die Verwendung von verschachtelten Variablen und komplexen Datenstrukturen wie Listen und Dictionaries. Dies ermöglicht eine noch größere Flexibilität bei der Definition von Konfigurationen.

Beispiel für komplexe Datenstrukturen:

---
- name: Beispiel Playbook mit verschachtelten Variablen
  hosts: all
  vars:
    users:
      - name: alice
        uid: 1001
      - name: bob
        uid: 1002

  tasks:
    - name: Erstelle Benutzer
      user:
        name: "{{ item.name }}"
        uid: "{{ item.uid }}"
      loop: "{{ users }}"

27.4.3 Dynamische Variablenberechnung

Ansible ermöglicht die dynamische Berechnung und Manipulation von Variablenwerten zur Laufzeit durch die Verwendung von Filtern und Jinja2-Templates.

Beispiel für die Verwendung von Jinja2-Filtern:

---
- name: Berechne dynamischen Wert
  hosts: all
  vars:
    base_path: "/var/www"
    site_name: "example"

  tasks:
    - name: Erstelle dynamisches Verzeichnis
      file:
        path: "{{ base_path }}/{{ site_name | lower }}"
        state: directory

Hier wird der Name des Verzeichnisses zur Laufzeit durch die Kombination und Verarbeitung mehrerer Variablen berechnet.

27.5 Arbeiten mit komplexen Datenstrukturen und Listen

Komplexe Datenstrukturen wie Listen und Dictionaries sind in Ansible äußerst nützlich, um strukturierte Daten zu verwalten und wiederverwendbare Konfigurationen zu erstellen.

27.5.1 Listen

Listen werden in YAML durch einfache Bindestriche definiert und ermöglichen es, mehrere Werte in einer geordneten Reihenfolge zu speichern.

Beispiel für eine Liste:

users:
  - alice
  - bob
  - charlie

27.5.2 Dictionaries

Dictionaries (Schlüssel-Wert-Paare) sind eine Möglichkeit, zusammengehörige Daten in einer nicht geordneten Struktur zu speichern.

Beispiel für ein Dictionary:

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

27.5.3 Kombination von Listen und Dictionaries

Sie können Listen und Dictionaries kombinieren, um komplexe Datenstrukturen zu erstellen, die sich hervorragend für die Verwaltung von Konfigurationen in Ansible eignen.

Beispiel für eine kombinierte Struktur:

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

Diese Struktur kann dann in Ansible-Tasks wie folgt verwendet werden:

tasks:
  - name: Erstelle Benutzer
    user:
      name: "{{ item.name }}"
      uid: "{{ item.uid }}"
      shell: "{{ item.shell }}"
    loop: "{{ users }}"

Diese Flexibilität in der Verwendung von Variablen ermöglicht es, Playbooks zu erstellen, die einfach zu warten, wiederverwendbar und auf verschiedene Anwendungsfälle anpassbar sind.