29 Playbook Rollen: Modularität und Wiederverwendbarkeit

29.1 Einführung und Definition

Rollen sind eine leistungsstarke Methode, um Ansible-Playbooks modular und wiederverwendbar zu gestalten. Sie ermöglichen es, Playbook-Logik in kleinere, überschaubare Einheiten zu zerlegen, die unabhängig voneinander entwickelt, getestet und wiederverwendet werden können. Rollen bündeln Aufgaben, Variablen, Handler, Dateien und Templates in einer strukturierten, wiederverwendbaren Form und fördern die Wiederverwendbarkeit von Code, was besonders in großen oder komplexen IT-Umgebungen von Vorteil ist.

29.2 Struktur von Rollen

29.2.1 Standardverzeichnisstruktur

Eine Rolle in Ansible folgt einer vordefinierten Verzeichnisstruktur, die bestimmte Standardverzeichnisse und Dateien enthält:

my_role/
├── tasks/            # Hauptaufgaben (Tasks) der Rolle
│   └── main.yml
├── handlers/         # Handler, die von der Rolle aufgerufen werden
│   └── main.yml
├── templates/        # Jinja2-Templates für dynamische Konfigurationsdateien
├── files/            # Statische Dateien, die die Rolle verwendet
├── vars/             # Variablen mit höherer Priorität
│   └── main.yml
├── defaults/         # Standardvariablen für die Rolle (niedrigste Priorität)
│   └── main.yml
├── meta/             # Metadaten über die Rolle (z.B. Abhängigkeiten)
│   └── main.yml
└── tests/            # Tests für die Rolle
    ├── inventory
    └── test.yml

29.2.2 Verzeichnisfunktionen im Detail

29.3 Playbooks vs. Rollen

Merkmal Playbook Rolle
Fokus Gesamtablauf und Orchestrierung Wiederverwendbare Teilschritte
Struktur Frei definierbar Standardisierte Ordnerstruktur
Wiederverwendung Selten Explizit vorgesehen
Kontext Umgebungsspezifisch Umgebungsunabhängig
Zweck Orchestrierung mehrerer Rollen Modularisierung spezifischer Funktionalitäten
Wartbarkeit Schwieriger bei Komplexität Einfacher durch Modularisierung

Playbooks orchestrieren den Gesamtablauf und definieren, welche Aufgaben auf welchen Hosts ausgeführt werden. Rollen kapseln spezifische Funktionalitäten als wiederverwendbare Module.

29.4 Erstellung von Rollen

29.4.1 Automatische Rollenerstellung

ansible-galaxy init my_role

Dieser Befehl erstellt eine neue Rolle mit der kompletten Standardverzeichnisstruktur.

29.4.2 Beispiel: Erstellung einer Apache-Rolle

Schritt 1: Aufgaben definieren (tasks/main.yml)

---
- name: Installiere Apache
  apt:
    name: apache2
    state: present
  notify: Starte Apache neu

- name: Kopiere Apache-Konfiguration
  template:
    src: apache.conf.j2
    dest: /etc/apache2/apache2.conf
  notify: Starte Apache neu

- name: Starte und aktiviere Apache
  service:
    name: apache2
    state: started
    enabled: yes

Schritt 2: Standardvariablen definieren (defaults/main.yml)

---
http_port: 80
https_port: 443
max_clients: 100
server_name: localhost
apache_modules:
  - rewrite
  - ssl

Schritt 3: Handler definieren (handlers/main.yml)

---
- name: Starte Apache neu
  service:
    name: apache2
    state: restarted

- name: Lade Apache-Konfiguration neu
  service:
    name: apache2
    state: reloaded

Schritt 4: Template erstellen (templates/apache.conf.j2)

ServerRoot /etc/apache2
Listen {{ http_port }}
{% if https_port is defined %}
Listen {{ https_port }} ssl
{% endif %}

ServerName {{ server_name }}
MaxRequestWorkers {{ max_clients }}

{% for module in apache_modules %}
LoadModule {{ module }}_module modules/mod_{{ module }}.so
{% endfor %}

29.5 Verwendung von Rollen in Playbooks

29.5.1 Grundlegende Rollenverwendung

---
- name: Webserver einrichten
  hosts: webservers
  roles:
    - common     # Grundkonfiguration
    - apache     # Webserver
    - php        # PHP-Umgebung

29.5.2 Parameterisierte Rollen

Rollen können durch Variablen an unterschiedliche Umgebungen angepasst werden:

---
- name: Webserver mit spezifischer Konfiguration
  hosts: webservers
  roles:
    - role: apache
      vars:
        http_port: 8080
        max_clients: 200
        server_name: "{{ inventory_hostname }}"
    - role: php
      php_version: "8.1"
      when: install_php | default(true)

29.5.3 Rollenbasierte Projektstruktur

In größeren Projekten empfiehlt sich eine strukturierte Herangehensweise:

ansible-project/
├── site.yml                    # Haupt-Playbook
├── group_vars/
│   ├── webservers.yml
│   └── dbservers.yml
├── host_vars/
├── inventories/
│   ├── production/
│   └── staging/
└── roles/
    ├── common/
    ├── nginx/
    ├── apache/
    ├── php/
    ├── mysql/
    └── monitoring/

Beispiel für site.yml:

---
- name: Konfiguriere alle Webserver
  hosts: webservers
  vars:
    environment_type: production
  roles:
    - common
    - apache
    - php
    - role: monitoring
      when: environment_type == "production"

- name: Konfiguriere Datenbankserver
  hosts: dbservers
  roles:
    - common
    - mysql
    - monitoring

29.6 Erweiterte Rollenkonzepte

29.6.1 Rollendependenzen

Rollen können Abhängigkeiten von anderen Rollen definieren, die automatisch vor der aktuellen Rolle ausgeführt werden:

# meta/main.yml
---
dependencies:
  - role: common
  - role: firewall
    firewall_allowed_ports:
      - 80
      - 443
  - role: monitoring
    when: enable_monitoring | default(false)

29.6.2 Import vs. Include von Rollen

Ansible bietet zwei Mechanismen, um Rollen in Playbooks einzubinden:

Kriterium import_role include_role
Zeitpunkt der Verarbeitung Zur Parsing-Zeit (statisch) Zur Laufzeit (dynamisch)
Bedingte Ausführung Eingeschränkt Vollständig unterstützt
Performance Schneller Etwas langsamer
Tags Übernimmt Tags vom Playbook Unterstützt eigene Tags
Loops Nicht unterstützt Vollständig unterstützt
Anwendungsfall Statische Rolleneinbindung Bedingte/dynamische Einbindung

Beispiel import_role:

- name: Statische Rolleneinbindung
  import_role:
    name: apache
  vars:
    http_port: 8080

Beispiel include_role:

- name: Dynamische Rolleneinbindung
  include_role:
    name: apache
  vars:
    http_port: 8080
  when: install_webserver | default(true)

- name: OS-spezifische Rollen
  include_role:
    name: "{{ ansible_os_family | lower }}_webserver"

29.7 Best Practices

29.7.1 Entwicklungsprinzipien

  1. Single Responsibility Principle: Jede Rolle sollte einen einzelnen, klar definierten Zweck haben
  2. Parametrisierung: Rollen sollten durch Variablen flexibel anpassbar sein
  3. Konsistente Namensgebung: Verwenden Sie eine einheitliche Namenskonvention (rolename_variable)
  4. Sinnvolle Defaultwerte: Definieren Sie brauchbare Standardwerte in defaults/main.yml

29.7.2 Modularität und Wiederverwendbarkeit

# Gutes Beispiel: Modulare Rollenverwendung
- name: Komplettes Webserver-Setup
  hosts: webservers
  vars:
    environment_type: production
  roles:
    # Basis-Konfiguration für alle Server
    - role: common
      
    # Webserver-spezifische Konfiguration
    - role: nginx
      nginx_worker_processes: "{{ ansible_processor_vcpus }}"
      nginx_worker_connections: 1024
      
    # Application Server
    - role: php
      php_version: "8.1"
      when: install_php | default(true)
      
    # Monitoring nur in Production
    - role: monitoring
      when: environment_type == "production"

29.7.3 Dokumentation und Wartbarkeit

29.7.4 Umgebungsmanagement

29.8 Qualitätssicherung und Testing

29.8.1 Testing mit Molecule

# Molecule für eine Rolle initialisieren
molecule init role my_role

# Tests ausführen
molecule test

# Testumgebung erstellen und testen
molecule create
molecule converge
molecule verify
molecule destroy

29.8.2 Lint-Checks und Validierung

# .ansible-lint Konfiguration
exclude_paths:
  - .cache/
  - .github/
rules:
  - yaml[line-length]
  - name[casing]
  - risky-file-permissions

29.8.3 CI/CD-Integration

# GitHub Actions Beispiel
name: Test Ansible Role
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: 3.9
      - name: Install dependencies
        run: |
          pip install ansible molecule[docker]
      - name: Run Molecule tests
        run: molecule test

29.8.4 Versionierung und Release-Management