Identifizierung und Behebung von Engpässen in langsamen Ansible-Playbooks
Beschleunigen Sie Ihre Ansible-Bereitstellungen drastisch, indem Sie Leistungsengpässe identifizieren und beseitigen. Dieser Leitfaden bietet praktische Schritte, Konfigurationsbeispiele und Best Practices für das Profiling langsamer Playbooks, die Optimierung der Faktenermittlung, die Verwaltung von Verbindungen und die Abstimmung der Aufgabenausführung. Lernen Sie, die Funktionen von Ansible für eine effiziente und schnelle Infrastrukturautomatisierung zu nutzen.
Identifizierung und Behebung von Engpässen in langsamen Ansible-Playbooks
Langsame Ansible-Playbooks sind frustrierend, weil die Verzögerung selten an einer offensichtlichen Stelle liegt. Ein Durchlauf kann ein paar Sekunden damit verbringen, Fakten zu sammeln, ein paar mehr, um SSH-Verbindungen zu öffnen, und dann Minuten, um Dateien einen Host nach dem anderen zu kopieren. Wenn Sie nur raten, optimieren Sie normalerweise das Falsche.
Beginnen Sie damit, zu messen, wo die Zeit hingeht. Beheben Sie dann zuerst die größte Verzögerungsquelle. In einer kleinen Umgebung kann dies eine einzelne Shell-Aufgabe sein, die jedes Mal einen Paketmanager ausführt. In einer größeren Umgebung sind es oft der Verbindungsaufbau, die Faktenermittlung, eine niedrige forks-Einstellung oder ein Playbook, das die Arbeit stärker serialisiert als beabsichtigt.
Grundlegendes zu Ansible-Leistungsmetriken
Bevor Sie sich mit spezifischen Optimierungstechniken befassen, ist es entscheidend zu verstehen, wie Sie die Leistung von Ansible messen und interpretieren können. Ansible bietet integrierte Zeitinformationen, die für die Diagnose von unschätzbarem Wert sein können.
Verwenden Sie Timing-Ausgaben vor ausführlichen Protokollen
Sehr ausführliche Ausgaben können bei Verbindungsproblemen helfen, sind aber für die Leistungsarbeit zu unübersichtlich. Ein saubererer erster Durchlauf ist der profile_tasks-Callback, der die Aufgabendauern am Ende des Durchlaufs anzeigt.
In ansible.cfg:
[defaults]
callbacks_enabled = profile_tasks
Führen Sie dann das Playbook normal aus:
ansible-playbook my_playbook.yml
Schauen Sie sich zuerst die langsamsten Aufgaben an. Wenn eine Aufgabe den Großteil des Durchlaufs beansprucht, verschwenden Sie den Morgen nicht mit Diskussionen über forks.
Steuerung der Ausgabeausführlichkeit
Verwenden Sie -vvv, wenn Sie SSH-Details, Modulübertragungsverhalten, Wiederholungen oder die Interpretererkennung sehen müssen. Für routinemäßige Zeitmessungen kann es das Signal unter Seiten von Protokollausgaben verbergen.
Häufige Engpässe und Optimierungsstrategien
Mehrere Faktoren können zu langsamen Ansible-Playbooks beitragen. Hier untersuchen wir häufige Engpässe und bieten umsetzbare Strategien zu deren Behebung.
1. Übermäßige Faktenermittlung
Standardmäßig sammelt Ansible Fakten (Systeminformationen) von verwalteten Hosts zu Beginn jedes Plays. Dies kann zwar nützlich sein, aber zeitaufwändig, insbesondere bei einer großen Anzahl von Hosts oder langsamen Netzwerken. Wenn Ihr Playbook nicht alle gesammelten Fakten benötigt, können Sie die Faktenermittlung deaktivieren oder einschränken.
Deaktivieren der Faktenermittlung
Um die Faktenermittlung für ein Play vollständig zu deaktivieren, verwenden Sie die Direktive gather_facts: no:
- name: Mein Playbook
hosts: webservers
gather_facts: no
tasks:
- name: Stellen Sie sicher, dass Apache installiert ist
apt: name=apache2 state=present
Einschränken der Faktenermittlung
Wenn Sie einige Fakten benötigen, aber nicht alle, können Sie mit gather_subset angeben, welche Fakten gesammelt werden sollen.
- name: Mein Playbook
hosts: webservers
gather_facts: yes
gather_subset:
- '!all'
- '!any'
- hardware
- network
tasks:
- name: Netzwerkfakten verwenden
debug: var=ansible_default_ipv4.address
Zwischenspeichern von Fakten
In Umgebungen, in denen sich Fakten nicht häufig ändern, kann deren Zwischenspeicherung nachfolgende Playbook-Durchläufe erheblich beschleunigen. Ansible unterstützt mehrere Fact-Caching-Plugins (z. B. jsonfile, redis, memcached).
Um das Zwischenspeichern von Fakten zu aktivieren, konfigurieren Sie es in Ihrer ansible.cfg-Datei:
[defaults]
fact_caching = jsonfile
fact_caching_connection = /path/to/ansible/facts_cache
fact_caching_timeout = 86400 # 24 Stunden zwischenspeichern
Ihr Playbook verwendet dann automatisch zwischengespeicherte Fakten, wenn verfügbar.
2. Ineffiziente Aufgabenausführung
Einige Aufgaben sind möglicherweise von Natur aus langsam oder werden auf ineffiziente Weise ausgeführt.
Parallele Ausführung (Forking)
Das Standardverhalten von Ansible besteht darin, Aufgaben innerhalb eines Plays sequenziell auf Hosts auszuführen. Sie können die Anzahl der parallelen Prozesse (Forks) erhöhen, die Ansible zur gleichzeitigen Verwaltung von Hosts verwendet. Dies wird durch die Einstellung forks in ansible.cfg oder über die Befehlszeilenoption -f gesteuert.
ansible.cfg:
[defaults]
forks = 10
Befehlszeile:
ansible-playbook my_playbook.yml -f 10
Tipp: Beginnen Sie mit einer moderaten Anzahl von Forks und erhöhen Sie diese schrittweise, während Sie den Kontrollknoten, das Netzwerk und den Zieldienst beobachten. Mehr Forks können eine Bereitstellung beschleunigen, aber sie können auch ein Paket-Repository, einen Load Balancer oder einen Datenbankmigrationsschritt überlasten.
Idempotenz und Zustandsverwaltung
Stellen Sie sicher, dass Ihre Aufgaben idempotent sind. Das bedeutet, dass das mehrmalige Ausführen einer Aufgabe denselben Effekt haben sollte wie das einmalige Ausführen. Ansible-Module sind im Allgemeinen so konzipiert, dass sie idempotent sind, aber benutzerdefinierte Skripte oder Befehle sind dies möglicherweise nicht. Ineffiziente Prüfungen innerhalb von Aufgaben können ebenfalls zu Mehraufwand führen.
Anstatt beispielsweise einen Befehl auszuführen, der prüft, ob ein Dienst läuft, und ihn dann startet, verwenden Sie das dedizierte service-Modul:
Ineffizient:
- name: Dienst starten (ineffiziente Prüfung)
command: systemctl start my_service.service || true
when: "'inactive' in service_status.stdout"
register: service_status
changed_when: false # Diese Aufgabe ändert den Zustand nicht
Effizient (mit dem service-Modul):
- name: Stellen Sie sicher, dass my_service läuft
service:
name: my_service
state: started
Verwenden von async und poll für langlaufende Operationen
Bei Aufgaben, deren Abschluss lange dauern kann (z. B. Paket-Upgrades, Datenbankmigrationen), können Sie mit den Direktiven async und poll von Ansible verhindern, dass Ihr Playbook hängt.
async: Gibt die maximale Zeit an, die die Aufgabe im Hintergrund laufen soll.poll: Gibt an, wie oft Ansible den Status der asynchronen Aufgabe überprüfen soll.
- name: Führen Sie eine langlaufende Operation aus
command: /usr/local/bin/long_script.sh
async: 3600 # Maximal 1 Stunde laufen
poll: 60 # Status alle 60 Sekunden überprüfen
3. Verbindungsoptimierung
Wie Ansible eine Verbindung zu Ihren verwalteten Knoten herstellt, spielt eine entscheidende Rolle für die Leistung.
SSH-Verbindungsmultiplexing
SSH-Multiplexing (ControlMaster) ermöglicht mehreren SSH-Sitzungen, eine einzige Netzwerkverbindung gemeinsam zu nutzen. Dies kann nachfolgende Verbindungen zum selben Host erheblich beschleunigen.
Aktivieren Sie es in Ihrer ansible.cfg:
[ssh_connection]
control_master = auto
control_path = ~/.ansible/cp/ansible-%%r@%%h:%%p
control_persist = 600 # Halten Sie die Steuerverbindung 10 Minuten lang offen
SSH-Wiederholungen und Timeout
Das Anpassen der SSH-Verbindungsparameter kann unnötige Verzögerungen verhindern, wenn Hosts vorübergehend nicht verfügbar sind.
[ssh_connection]
sf_retries = 3
sf_delay = 1
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ConnectionAttempts=5 -o ConnectTimeout=10
Verwenden von pipelining
Pipelining ermöglicht es Ansible, Befehle direkt auf dem entfernten Host auszuführen, ohne für jeden Befehl eine neue SSH-Sitzung zu erstellen. Dies kann den Overhead für viele Aufgaben drastisch reduzieren.
Aktivieren Sie es in ansible.cfg:
[ssh_connection]
pipelining = True
Warnung: Pipelining kann mit einigen Konfigurationen zur Rechteausweitung in Konflikt geraten, insbesondere wenn requiretty für sudo auf älteren Distributionen aktiviert ist. Testen Sie es mit demselben become-Pfad, den Ihre Produktions-Playbooks verwenden.
4. Optimierung der Playbook-Struktur und -Logik
Manchmal liegt die Ursache für Langsamkeit in der Art und Weise, wie ein Playbook geschrieben ist.
Verwenden von delegate_to und run_once
Wenn eine Aufgabe nur auf einem Host ausgeführt werden muss, aber mehrere andere betrifft (z. B. Neustart eines Load Balancers), verwenden Sie delegate_to und run_once, um sie effizient auszuführen.
- name: Load Balancer neu starten
service: name=haproxy state=restarted
delegate_to: lb_server_1
run_once: true
Strategische Verwendung von Rollen und Includes
Während Rollen und Includes bei der Organisation helfen, können tief verschachtelte oder ineffizient strukturierte Includes einen kleinen Overhead verursachen. Stellen Sie sicher, dass Ihre Rollenabhängigkeiten und Ihre Include-Logik sauber sind.
serial-Schlüsselwort
Das Schlüsselwort serial begrenzt die Anzahl der Hosts, die innerhalb eines Plays gleichzeitig bearbeitet werden können. Obwohl es oft für kontrollierte Rollouts verwendet wird, kann es auch ein Engpass sein, wenn es für die gewünschte Leistung zu niedrig eingestellt ist.
- name: Anwendung auf einer Teilmenge von Servern bereitstellen
hosts: appservers
serial: 2 # Nur auf 2 Hosts gleichzeitig ausführen
tasks:
- name: Anwendungscode aktualisieren
copy: src=app/ dest=/opt/app/
Wenn Sie die Parallelität nicht absichtlich einschränken, stellen Sie sicher, dass serial nicht gesetzt oder auf eine ausreichend hohe Zahl gesetzt ist.
Langsame Aufgaben beheben, nicht nur langsamen Transport
Die Verbindungsoptimierung hilft, wenn das Playbook viele kurze Aufgaben hat. Sie behebt keine Aufgabe, die jedes Mal zu viel Arbeit leistet.
Ein häufiges Beispiel ist die Verwendung von shell, um einen Paketbefehl auszuführen:
- name: Installiere nginx mit shell
shell: apt-get update && apt-get install -y nginx
Diese Aufgabe ist für Ansible schwer zu durchschauen. Sie kann jedes Mal als geändert gemeldet werden, sie kann bei jedem Durchlauf Paketmetadaten aktualisieren und gibt Ihnen weniger strukturierte Fehlerinformationen. Bevorzugen Sie Module, die den Zustand verstehen:
- name: Aktualisiere den apt-Cache bei Bedarf
apt:
update_cache: true
cache_valid_time: 3600
- name: Installiere nginx
apt:
name: nginx
state: present
Die gleiche Idee gilt für die Dateibereitstellung. Das Kopieren eines großen Verzeichnisses mit Hunderten von kleinen Dateien über das copy-Modul kann langsam sein, da Ansible Datei für Datei prüft und überträgt. Für Anwendungsfreigaben kann es schneller sein, ein Artefakt einmal zu erstellen, das Archiv hochzuladen und es auf dem Ziel zu entpacken:
- name: Lade das Release-Artefakt hoch
copy:
src: dist/app.tar.gz
dest: /tmp/app.tar.gz
- name: Entpacke das Release
unarchive:
src: /tmp/app.tar.gz
dest: /opt/app
remote_src: true
Das ist nicht immer das richtige Design, aber es ist die richtige Frage: Bitten Sie Ansible, Tausende von winzigen Entscheidungen zu synchronisieren, wenn ein Artefakt klarer wäre?
Überprüfen Sie das Inventar und die Variablenarbeit
Ein dynamisches Inventar kann eine weitere versteckte Verzögerung sein. Wenn jeder Playbook-Durchlauf eine Cloud-API aufruft, auf Paginierung wartet und die gesamte Hostliste neu aufbaut, kann sich das Playbook langsam anfühlen, bevor die erste Aufgabe beginnt. Zwischenspeichern Sie Inventardaten, wenn Ihr Plugin dies unterstützt, und halten Sie Host-Muster eng. Das Ausführen einer Web-Bereitstellung gegen all und das Überspringen der meisten Hosts mit when-Bedingungen verschwendet Zeit.
Das Laden von Variablen kann ebenfalls unübersichtlich werden. Große group_vars/all.yml-Dateien, teure Lookups und wiederholtes Template-Rendering können sich summieren. Wenn ein Lookup einen Secrets-Manager oder HTTP-Endpunkt erreicht, speichern Sie das Ergebnis einmal pro Play in einer Variablen, anstatt es in vielen Aufgaben aufzurufen.
Profiling-Tools und -Techniken
Über die ausführliche Ausgabe von Ansible selbst hinaus kann ein dediziertes Profiling tiefere Einblicke bieten.
ansible-playbook --syntax-check
Dieser Befehl überprüft Ihr Playbook auf Syntaxfehler, führt es aber nicht aus. Es ist eine schnelle Möglichkeit, die Struktur Ihres Playbooks vor einem vollständigen Durchlauf zu validieren.
Protokollierung von Ansible-Ereignissen
Ansible kann seine Ausführungsereignisse in einer Datei protokollieren, die dann analysiert werden kann. Dies ist besonders nützlich für langlaufende Playbooks oder für die Überwachung.
Konfigurieren Sie die Ereignisprotokollierung in ansible.cfg:
[defaults]
log_path = /var/log/ansible.log
Benutzerdefinierte Callback-Plugins
Für fortgeschrittenes Profiling können Sie benutzerdefinierte Callback-Plugins schreiben, um bestimmte Metriken zu erfassen oder benutzerdefinierte Berichte zur Playbook-Ausführung zu erstellen.
Verwenden Sie Async zum Warten, nicht für alles
Ein Teil der Playbook-Zeit ist echtes Warten: ein Neustart eines Dienstes, ein Paketbuild, eine Cloud-Instanz, die bereit wird, oder eine Datenbankmigration, die legitimerweise ein paar Minuten dauert. Wenn diese Aufgaben nicht jeden Host im Gleichschritt blockieren müssen, können die async- und poll-Funktionen von Ansible helfen.
- name: Starte die langlaufende Berichtsgenerierung
command: /opt/tools/build-report
async: 1800
poll: 0
register: report_job
- name: Überprüfe den Berichtsjob
async_status:
jid: "{{ report_job.ansible_job_id }}"
register: report_status
until: report_status.finished
retries: 60
delay: 10
Verwenden Sie dies mit Bedacht. Async ist keine Abkürzung, um unsichere Aufgaben parallel zu machen. Wenn zehn Hosts gleichzeitig eine Datenbankmigration starten, wird das Playbook möglicherweise schneller fertig und trotzdem die Umgebung beschädigen. Async funktioniert am besten für unabhängige Arbeiten, bei denen das Ziel sicher fortfahren kann, während Ansible später zurückkommt.
Messen Sie aus der Sicht des Benutzers
Ein Playbook kann technisch schneller sein und sich dennoch langsam anfühlen, wenn der Bediener zu lange wartet, bevor er nützliches Feedback sieht. Teilen Sie eine große Bereitstellung in Phasen mit klaren Aufgabennamen auf: Preflight-Checks, Artefakt-Upload, Service-Update, Health Check, Bereinigung. Wenn eine Phase langsam ist, verstehen sowohl die Profilausgabe als auch der Mensch, der das Terminal liest, wo die Zeit geblieben ist.
Dies hilft auch bei Rollback-Entscheidungen. Wenn das Playbook 12 Minuten vor dem ersten Health Check verbringt, entdecken Sie Fehler möglicherweise zu spät. Eine kleine Preflight-Aufgabe, die Festplattenplatz, Paket-Repository-Zugriff und Service-Anmeldeinformationen überprüft, kann weit mehr Zeit sparen, als eine Sekunde vom SSH-Setup abzuzwacken.
Die beste Ansible-Leistungsarbeit ist auf eine gute Weise langweilig: Aktivieren Sie die Aufgabenzeitmessung, finden Sie den langsamsten Schritt, ändern Sie eine Sache und messen Sie erneut. Deaktivieren Sie Fakten nur, wenn Sie sie nicht benötigen. Erhöhen Sie forks nur, wenn die Ziele und Abhängigkeiten die Parallelität verarbeiten können. Ersetzen Sie laute Shell-Befehle durch zustandsbewusste Module. Verwenden Sie SSH-Multiplexing und Pipelining, nachdem Sie bestätigt haben, dass der Verbindungs-Overhead tatsächlich Teil des Problems ist.
Diese Disziplin hält das Playbook lesbar und macht es gleichzeitig schneller. Eine Bereitstellung, die schnell abgeschlossen ist, aber niemand versteht, ist nur der morgige Ausfall mit einer kürzeren Fortschrittsanzeige.