33 Playbook-Strategien für große Umgebungen

33.1 Skalierbarkeit und Verwaltung großer Playbooks

In großen IT-Umgebungen, die Hunderte oder Tausende von Hosts umfassen, müssen Playbooks so gestaltet werden, dass sie sowohl skalierbar als auch wartbar sind. Das Ziel ist es, die Komplexität zu reduzieren, indem Playbooks modular aufgebaut und in kleinere, handhabbare Einheiten zerlegt werden.

33.1.1 Aufteilung von Playbooks

Eine der effektivsten Strategien zur Verwaltung großer Playbooks besteht darin, diese in mehrere kleinere Playbooks zu unterteilen, die jeweils eine spezifische Aufgabe oder Rolle abdecken. Diese können dann nach Bedarf kombiniert oder in einer bestimmten Reihenfolge ausgeführt werden.

Beispielstruktur:

site.yml  # Haupt-Playbook, das andere Playbooks aufruft
webservers.yml  # Playbook zur Konfiguration von Webservern
dbservers.yml  # Playbook zur Konfiguration von Datenbankservern
loadbalancers.yml  # Playbook zur Konfiguration von Load Balancern

Beispiel für ein Haupt-Playbook mit import_playbook (empfohlen seit Ansible 2.4):

---
# Moderne Ansible-Syntax für bessere Performance und Fehlerbehandlung
- import_playbook: webservers.yml
- import_playbook: dbservers.yml
- import_playbook: loadbalancers.yml

Hinweis: Während include zur Laufzeit evaluiert wird, wird import_playbook zur Parse-Zeit verarbeitet, was zu besserer Performance und frühzeitiger Fehlererkennung führt.

33.1.2 Verwendung von Rollen zur Modularisierung

Rollen sollten genutzt werden, um wiederverwendbare und modulare Playbooks zu erstellen. Jede Rolle sollte eine klar definierte Aufgabe haben und in sich abgeschlossen sein, sodass sie unabhängig getestet und verwaltet werden kann.

Beispiel für die Verwendung von Rollen:

---
- name: Einrichtung einer kompletten Webserver-Umgebung
  hosts: webservers
  roles:
    - common  # Rolle für allgemeine Aufgaben wie Benutzerverwaltung, Security-Updates
    - nginx   # Rolle zur Konfiguration von Nginx als Webserver
    - php     # Rolle zur Installation und Konfiguration von PHP

33.1.3 Dynamische Playbook-Ausführung mit Tags

Tags können verwendet werden, um spezifische Teile eines Playbooks selektiv auszuführen, ohne das gesamte Playbook durchlaufen zu müssen. Dies ist besonders nützlich, wenn Sie nur einen bestimmten Teil Ihrer Infrastruktur aktualisieren oder testen möchten.

Beispiel für die Verwendung von Tags:

---
- name: Installiere und konfiguriere Nginx
  hosts: webservers
  tasks:
    - name: Installiere Nginx
      apt:
        name: nginx
        state: present
      tags:
        - install
        - nginx

    - name: Konfiguriere Nginx
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      tags:
        - configure
        - nginx

Ausführung eines spezifischen Teils des Playbooks:

ansible-playbook site.yml --tags "install"

33.2 Dynamische Inventories für große Umgebungen

In großen, dynamischen Umgebungen reichen statische Inventory-Dateien oft nicht aus. Dynamische Inventories ermöglichen es, Host-Informationen zur Laufzeit aus externen Quellen abzurufen.

33.2.1 Cloud-Provider Integration

Beispiel für AWS EC2 Dynamic Inventory:

# aws_ec2.yml
plugin: aws_ec2
regions:
  - us-east-1
  - eu-west-1
keyed_groups:
  - key: tags
    prefix: tag
  - key: instance_type
    prefix: instance_type
compose:
  ansible_host: public_ip_address

Ausführung mit dynamischem Inventory:

ansible-playbook -i aws_ec2.yml site.yml

33.2.2 Custom Inventory Scripts

Für spezielle Umgebungen können eigene Inventory-Scripts entwickelt werden:

#!/usr/bin/env python3
# custom_inventory.py
import json
import requests

def get_inventory():
    # Abrufen der Host-Informationen aus CMDB/API
    response = requests.get('https://cmdb.company.com/api/hosts')
    hosts_data = response.json()
    
    inventory = {
        '_meta': {'hostvars': {}},
        'webservers': {'hosts': []},
        'dbservers': {'hosts': []}
    }
    
    for host in hosts_data:
        group = host['role'] + 'servers'
        if group in inventory:
            inventory[group]['hosts'].append(host['name'])
            inventory['_meta']['hostvars'][host['name']] = {
                'ansible_host': host['ip'],
                'environment': host['env']
            }
    
    return inventory

if __name__ == '__main__':
    print(json.dumps(get_inventory(), indent=2))

33.3 Umgang mit verteilten Systemen und komplexen Abhängigkeiten

In großen Umgebungen, insbesondere in verteilten Systemen, müssen Playbooks in der Lage sein, komplexe Abhängigkeiten zwischen verschiedenen Komponenten zu verwalten. Dies erfordert eine sorgfältige Planung und Strukturierung der Playbooks.

33.3.1 Abhängigkeitsmanagement mit Rollen

Rollen können so gestaltet werden, dass sie ihre Abhängigkeiten selbst verwalten. Dies kann in der meta/main.yml der Rolle definiert werden, um sicherzustellen, dass benötigte Rollen oder Tasks vor der Ausführung bereitgestellt werden.

Beispiel für Abhängigkeiten in einer Rolle:

---
# meta/main.yml der nginx-Rolle
dependencies:
  - role: common
    vars:
      some_var: 42
  - role: ssl_certificates
    when: nginx_ssl_enabled | default(false)

33.3.2 Koordination von Aufgaben über mehrere Hosts hinweg

Manchmal müssen Aufgaben in einer bestimmten Reihenfolge auf verschiedenen Hosts ausgeführt werden. Ansible bietet Mechanismen, um sicherzustellen, dass Tasks auf verschiedenen Hosts koordiniert werden, z.B. durch die Verwendung von serial oder wait_for.

Beispiel für koordinierte Aufgaben:

---
- name: Verteile Konfigurationen und starte Services in der richtigen Reihenfolge
  hosts: webservers
  serial: 1
  tasks:
    - name: Verteilen der Konfiguration
      template:
        src: webserver.conf.j2
        dest: /etc/webserver.conf

    - name: Starte den Webserver
      service:
        name: webserver
        state: started
    
    - name: Warte auf Service-Verfügbarkeit
      wait_for:
        port: 80
        host: "{{ ansible_host }}"
        timeout: 30

33.3.3 Enterprise-Best-Practices für Inventory-Struktur

Empfohlene Verzeichnisstruktur für große Umgebungen:

inventories/
├── production/
│   ├── hosts.yml
│   ├── group_vars/
│   │   ├── all.yml
│   │   ├── webservers.yml
│   │   └── dbservers.yml
│   └── host_vars/
│       ├── web01.yml
│       └── db01.yml
├── staging/
│   ├── hosts.yml
│   └── group_vars/
└── development/
    ├── hosts.yml
    └── group_vars/

Beispiel für hierarchische Gruppierung:

# inventories/production/hosts.yml
all:
  children:
    europe:
      children:
        germany:
          children:
            frankfurt:
              hosts:
                web01.fra.company.com:
                web02.fra.company.com:
            munich:
              hosts:
                web03.muc.company.com:
    americas:
      children:
        usa:
          children:
            east:
              hosts:
                web01.nyc.company.com:

33.4 Verwaltung von Playbook-Versionen und Konfigurationen

In großen Umgebungen ist es wichtig, dass Playbook-Versionen und Konfigurationen konsistent und nachvollziehbar verwaltet werden. Dies kann durch den Einsatz von Versionskontrollsystemen und durch das Einführen von Versionskennzeichnungen in Playbooks und Konfigurationsdateien erreicht werden.

33.4.1 Git-Strategien für Multi-Environment-Setups

Feature Branch Workflow für Playbooks:

# Entwicklung neuer Features
git checkout -b feature/nginx-optimization
# ... Änderungen an Playbooks
git commit -m "Add nginx performance tuning"
git push origin feature/nginx-optimization

# Merge über Pull Request nach Code Review
# Deployment auf verschiedene Umgebungen
git checkout main
git tag v1.2.3

Environment-spezifische Branches:

# Struktur für verschiedene Umgebungen
main          # Produktionsreife Version
├── staging   # Staging-Umgebung
└── develop   # Entwicklungsumgebung

33.4.2 Verwendung von Versionskontrolle (Git)

Playbooks sollten in einem Versionskontrollsystem wie Git verwaltet werden, um Änderungen nachverfolgen und Rollbacks durchführen zu können. Dies ermöglicht es auch, mehrere Versionen eines Playbooks parallel zu verwalten (z.B. für verschiedene Umgebungen).

Beispiel für die Verwaltung von Playbooks in Git:

git init
git add playbooks/
git commit -m "Initial commit: Basic infrastructure playbooks"
git tag v1.0.0

33.4.3 Kennzeichnung von Versionen

Versionskennzeichnungen in Playbooks und Konfigurationsdateien helfen dabei, sicherzustellen, dass immer die richtige Version eines Playbooks ausgeführt wird, insbesondere in Umgebungen mit mehreren Teams oder Releases.

Beispiel für eine Versionskennzeichnung in einem Playbook:

---
# Version 1.2.3 - Nginx Performance Optimization
- name: Setup Webserver
  hosts: webservers
  vars:
    playbook_version: "1.2.3"
    playbook_name: "webserver-setup"
  pre_tasks:
    - name: Log Playbook-Version
      debug:
        msg: "Executing {{ playbook_name }} version {{ playbook_version }}"

33.5 Automatisierung von Playbook-Deployments in großen IT-Umgebungen

Die Automatisierung von Playbook-Deployments ist ein entscheidender Faktor für die Skalierbarkeit und Zuverlässigkeit in großen IT-Umgebungen. Durch die Integration von Ansible in CI/CD-Pipelines und die Automatisierung des gesamten Deployments kann sichergestellt werden, dass Playbooks konsistent und schnell auf eine große Anzahl von Hosts angewendet werden.

33.5.1 Integration von Ansible in CI/CD-Pipelines

Die Integration von Ansible in CI/CD-Pipelines ermöglicht es, Playbooks automatisch nach jeder Codeänderung oder jedem Commit auszuführen. Dies gewährleistet, dass Änderungen schnell und zuverlässig auf allen benötigten Systemen ausgerollt werden.

Beispiel für eine GitLab CI-Konfiguration:

stages:
  - validate
  - deploy-staging
  - deploy-production

variables:
  ANSIBLE_HOST_KEY_CHECKING: "False"

validate_playbooks:
  stage: validate
  script:
    - ansible-playbook --syntax-check site.yml
    - ansible-lint playbooks/

deploy_staging:
  stage: deploy-staging
  script:
    - ansible-playbook -i inventories/staging site.yml
  only:
    - develop

deploy_production:
  stage: deploy-production
  script:
    - ansible-playbook -i inventories/production site.yml
  only:
    - main
  when: manual

33.5.2 Automatisiertes Rollout mit ansible-pull

In einigen Szenarien kann es sinnvoll sein, die Hosts selbst die Playbooks abrufen und ausführen zu lassen, anstatt sie zentral zu pushen. Dies kann durch die Verwendung von ansible-pull erreicht werden, was besonders in dynamischen Umgebungen nützlich ist.

Beispiel für die Verwendung von ansible-pull:

# Auf dem Ziel-Host
ansible-pull -U https://github.com/myrepo/playbooks.git \
             -d /opt/ansible \
             -i localhost, \
             site.yml

Cron-Job für regelmäßige Updates:

# /etc/cron.d/ansible-pull
*/30 * * * * root /usr/local/bin/ansible-pull -U https://github.com/company/ansible-configs.git -d /opt/ansible -i localhost, local.yml >> /var/log/ansible-pull.log 2>&1

33.5.3 Verwendung von Orchestrierungstools

In sehr großen Umgebungen kann es notwendig sein, zusätzliche Orchestrierungstools zu verwenden, um die Ausführung von Playbooks über mehrere Rechenzentren oder Cloud-Regionen hinweg zu koordinieren.

Beispiele für Orchestrierungstools:

33.5.4 Performance-Optimierung für große Deployments

Parallelisierung und Batch-Processing:

---
- name: Large Scale Deployment
  hosts: all
  strategy: linear
  serial: 
    - 10%    # Starte mit 10% der Hosts
    - 50%    # Dann 50%
    - 100%   # Schließlich alle
  max_fail_percentage: 5
  
  tasks:
    - name: Deploy Application
      include_tasks: deploy_app.yml

Ansible-Konfiguration für bessere Performance:

# ansible.cfg
[defaults]
host_key_checking = False
gathering = smart
fact_caching = memory
fact_caching_timeout = 86400
forks = 50
pipelining = True

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
control_path = /tmp/ansible-ssh-%%h-%%p-%%r

33.6 Monitoring und Fehlerbehandlung in großen Deployments

33.6.1 Structured Logging und Callbacks

Beispiel für Custom Callback Plugin:

# callback_plugins/deployment_tracker.py
from ansible.plugins.callback import CallbackBase
import json
import requests

class CallbackModule(CallbackBase):
    def v2_playbook_on_stats(self, stats):
        # Sende Deployment-Status an Monitoring-System
        summary = {
            'timestamp': datetime.now().isoformat(),
            'hosts_ok': len(stats.ok),
            'hosts_failed': len(stats.failures),
            'hosts_unreachable': len(stats.dark)
        }
        
        requests.post('https://monitoring.company.com/api/deployments', 
                     json=summary)

33.6.2 Rollback-Strategien

Automatischer Rollback bei Fehlern:

---
- name: Application Deployment with Rollback
  hosts: webservers
  vars:
    app_version: "{{ ansible_date_time.epoch }}"
  
  tasks:
    - name: Create Backup
      command: cp -r /opt/app /opt/app.backup.{{ app_version }}
    
    - name: Deploy New Version
      unarchive:
        src: "app-{{ version }}.tar.gz"
        dest: /opt/app
      register: deploy_result
      
    - name: Rollback on Failure
      command: |
        rm -rf /opt/app
        mv /opt/app.backup.{{ app_version }} /opt/app
      when: deploy_result is failed