In großen IT-Umgebungen können Playbooks mit Hunderten von Hosts oder zeitaufwändigen Tasks schnell zu Engpässen werden. Dieses Kapitel zeigt Ihnen, wie Sie durch gezielte Optimierungsstrategien die Ausführungszeit drastisch reduzieren und gleichzeitig die Zuverlässigkeit Ihrer Automatisierung erhöhen können.
Lernziele:
serial, throttle, forks)forksDie grundlegende Parallelität in Ansible wird über die
forks-Einstellung in der ansible.cfg
gesteuert:
# ansible.cfg
[defaults]
forks = 20
host_key_checking = False
gathering = smart
fact_caching = memoryStandard: 5 parallele Verbindungen
Empfehlung: 10-50 je nach Netzwerk und Ziel-Hosts
serialDer serial-Parameter steuert, wie viele Hosts
gleichzeitig bearbeitet werden - ideal für Rolling Updates:
---
- name: Rolling Update mit serial
hosts: webservers
serial: "30%" # Prozentual oder absolute Zahl (z.B. 5)
tasks:
- name: Stoppe Service
service:
name: apache2
state: stopped
- name: Update Anwendung
copy:
src: app-v2.0.tar.gz
dest: /opt/app/
- name: Starte Service
service:
name: apache2
state: started
- name: Warte auf Verfügbarkeit
uri:
url: "http://{{ ansible_host }}:80/health"
status_code: 200
retries: 5
delay: 10throttleDer throttle-Parameter begrenzt die Anzahl gleichzeitig
ausgeführter Instanzen eines bestimmten Tasks:
---
- name: Beispiel für ressourcenintensive Tasks
hosts: all
tasks:
- name: Datenbank-Backup (ressourcenintensiv)
shell: |
mysqldump --all-databases > /backup/db_{{ ansible_date_time.epoch }}.sql
gzip /backup/db_{{ ansible_date_time.epoch }}.sql
throttle: 2 # Nur 2 Hosts gleichzeitig
- name: Normale Tasks ohne Begrenzung
apt:
name: htop
state: presentasync und poll---
- name: Demonstration asynchroner Tasks
hosts: all
tasks:
- name: Starte lange Aufgabe asynchron
command: /usr/bin/long_running_script.sh
async: 3600 # Max. 60 Minuten Laufzeit
poll: 30 # Prüfe alle 30 Sekunden
register: long_task
- name: Führe andere Tasks parallel aus
apt:
name: "{{ item }}"
state: present
loop:
- vim
- curl
- wget
- name: Warte auf Abschluss der langen Aufgabe
async_status:
jid: "{{ long_task.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 120
delay: 30poll: 0---
- name: Starte Hintergrund-Tasks
hosts: all
tasks:
- name: Starte Monitoring-Agent im Hintergrund
shell: |
nohup /opt/monitoring/agent --daemon > /dev/null 2>&1 &
async: 1
poll: 0
register: bg_task
# Wichtig: Job-ID für spätere Referenz speichern
- name: Speichere Job-IDs für spätere Kontrolle
set_fact:
background_jobs: "{{ background_jobs | default([]) + [bg_task.ansible_job_id] }}"---
- name: Komplexe asynchrone Verarbeitung
hosts: database_servers
tasks:
- name: Starte mehrere Backups parallel
shell: |
mysqldump {{ item }} > /backup/{{ item }}_{{ ansible_date_time.epoch }}.sql
async: 1800
poll: 0
register: backup_jobs
loop:
- app_db
- user_db
- log_db
- name: Prüfe Status aller Backup-Jobs
async_status:
jid: "{{ item.ansible_job_id }}"
register: backup_status
until: backup_status.finished
retries: 60
delay: 30
loop: "{{ backup_jobs.results }}"
when: item.ansible_job_id is defined
- name: Validiere erfolgreiche Backups
stat:
path: "/backup/{{ item }}_{{ ansible_date_time.epoch }}.sql"
register: backup_files
loop:
- app_db
- user_db
- log_db
failed_when: not backup_files.stat.exists---
- name: Optimierte Deployment-Pipeline
hosts: production
serial: 2
vars:
deployment_timeout: 1200
tasks:
- block:
- name: Erstelle Deployment-Backup asynchron
shell: |
tar -czf /backup/pre-deploy-{{ ansible_date_time.epoch }}.tar.gz /opt/app
async: "{{ deployment_timeout }}"
poll: 5
throttle: 1 # Nur ein Backup gleichzeitig
- name: Stoppe Anwendung graceful
service:
name: myapp
state: stopped
timeout: 60
- name: Deploy neue Version
unarchive:
src: "{{ app_package }}"
dest: /opt/app
remote_src: no
owner: app
group: app
- name: Starte Anwendung
service:
name: myapp
state: started
- name: Validiere Deployment
uri:
url: "http://{{ ansible_host }}:8080/health"
status_code: 200
retries: 10
delay: 15
rescue:
- name: Rollback bei Fehler
shell: |
systemctl stop myapp
rm -rf /opt/app/*
tar -xzf /backup/pre-deploy-*.tar.gz -C /
systemctl start myapp
register: rollback_result
- name: Benachrichtige bei Rollback
debug:
msg: "WARNUNG: Rollback ausgeführt auf {{ inventory_hostname }}"---
- name: Optimiertes Variablenmanagement
hosts: all
vars:
# Lazy evaluation - wird nur berechnet wenn benötigt
app_config_path: "{{ '/etc/myapp' if ansible_os_family == 'Debian' else '/opt/myapp/etc' }}"
# Teure Berechnung nur einmal durchführen
package_list: "{{ lookup('file', '/etc/required_packages.txt').splitlines() | select('match', '^[^#].*') | list }}"
tasks:
- name: Cache häufig verwendete Werte
set_fact:
system_info: {
'os': "{{ ansible_distribution }}",
'version': "{{ ansible_distribution_version }}",
'arch': "{{ ansible_architecture }}",
'memory_mb': "{{ ansible_memtotal_mb }}"
}
cacheable: yes # Wird zwischen Playbook-Runs gespeichert
- name: Verwende gecachte Werte
debug:
msg: "System: {{ system_info.os }} {{ system_info.version }} ({{ system_info.arch }})"
- name: Installiere Pakete mit vordefinierter Liste
package:
name: "{{ package_list }}"
state: present---
- name: Effiziente Fact-Sammlung
hosts: all
gather_facts: no # Deaktiviert automatische Sammlung
tasks:
- name: Sammle nur benötigte Facts
setup:
gather_subset:
- "!all"
- "!any"
- network
- hardware
when: custom_facts_needed | default(false)
- name: Verwende spezifische Facts nur bei Bedarf
set_fact:
network_interface: "{{ ansible_default_ipv4.interface | default('eth0') }}"
when: ansible_default_ipv4 is defined# Detaillierte Profiling-Informationen
ansible-playbook playbook.yml \
--profile_tasks \
--diff \
--check \
-v
# Mit zusätzlichen Callback-Plugins
ANSIBLE_STDOUT_CALLBACK=profile_tasks \
ANSIBLE_CALLBACK_WHITELIST=profile_tasks,timer \
ansible-playbook playbook.yml# ansible.cfg - Optimierte Konfiguration
[defaults]
forks = 25
host_key_checking = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600
pipelining = True
callback_whitelist = profile_tasks, timer
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
control_path_dir = ~/.ansible/cp
control_path = %(directory)s/%%h-%%p-%%r
pipelining = True---
- name: Performance-Testplaybook
hosts: all
vars:
start_time: "{{ ansible_date_time.epoch }}"
tasks:
- name: Markiere Startzeit für kritischen Abschnitt
set_fact:
section_start: "{{ ansible_date_time.epoch }}"
- name: Kritische Tasks hier...
# Ihre zeitkritischen Tasks
- name: Berechne Ausführungszeit
set_fact:
section_duration: "{{ ansible_date_time.epoch | int - section_start | int }}"
- name: Logge Performance-Metriken
debug:
msg: |
Performance-Report für {{ inventory_hostname }}:
- Gesamtzeit: {{ ansible_date_time.epoch | int - start_time | int }}s
- Kritischer Abschnitt: {{ section_duration }}s
- Memory: {{ ansible_memtotal_mb }}MB
when: section_duration | int > 30 # Nur bei langsamen Hosts