Ansible-Grundlagen, ohne die Ihre Playbooks ein Klumpen klebriger Nudeln wären

Ich überprüfe häufig den Ansible-Code anderer Leute und schreibe selbst viel. Im Zuge der Analyse von Fehlern (sowohl anderer als auch meiner eigenen) sowie einer Reihe von Interviews wurde mir der Hauptfehler klar, den Ansible-Benutzer machen: Sie stürzen sich in komplexe Dinge, ohne die grundlegenden zu beherrschen.

Um diese allgemeine Ungerechtigkeit zu korrigieren, habe ich beschlossen, eine Einführung in Ansible für diejenigen zu schreiben, die es bereits kennen. Ich warne Sie, dies ist keine Nacherzählung von Mans, dies ist eine lange Lektüre mit vielen Briefen und ohne Bilder.

Das erwartete Niveau des Lesers ist, dass bereits mehrere tausend Zeilen Yamla geschrieben wurden, etwas bereits in Produktion ist, aber „irgendwie alles schief ist“.

Titel

Der Hauptfehler, den ein Ansible-Benutzer macht, besteht darin, nicht zu wissen, wie etwas heißt. Wenn Sie die Namen nicht kennen, können Sie nicht verstehen, was in der Dokumentation steht. Ein lebendiges Beispiel: Während eines Interviews konnte eine Person, die zu sagen schien, dass sie viel in Ansible schrieb, die Frage „Aus welchen Elementen besteht ein Playbook?“ nicht beantworten. Und als ich vorschlug, dass „die Antwort erwartet wurde, dass das Spielbuch aus Spielen besteht“, folgte der vernichtende Kommentar „Das verwenden wir nicht“. Die Leute schreiben Ansible für Geld und verwenden kein Spiel. Sie verwenden es tatsächlich, wissen aber nicht, was es ist.

Beginnen wir also mit etwas Einfachem: Wie heißt es? Vielleicht wissen Sie das, vielleicht wissen Sie es auch nicht, weil Sie beim Lesen der Dokumentation nicht aufgepasst haben.

ansible-playbook führt das Playbook aus. Ein Playbook ist eine Datei mit der Erweiterung yml/yaml, in der sich etwa Folgendes befindet:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

Wir haben bereits erkannt, dass es sich bei dieser gesamten Datei um ein Playbook handelt. Wir können zeigen, wo die Rollen sind und wo die Aufgaben sind. Aber wo ist Spiel? Und was ist der Unterschied zwischen Spiel und Rolle oder Spielbuch?

Es steht alles in der Dokumentation. Und sie vermissen es. Anfänger – weil es zu viel ist und man sich nicht alles auf einmal merken kann. Erfahren – weil „triviale Dinge“. Wenn Sie Erfahrung haben, lesen Sie diese Seiten mindestens alle sechs Monate noch einmal, dann wird Ihr Code zum Klassenbesten.

Denken Sie also daran: Playbook ist eine Liste bestehend aus Play und import_playbook.
Dies ist ein Stück:

- hosts: group1
  roles:
    - role1

und das ist auch ein anderes Stück:

- hosts: group2,group3
  tasks:
    - debug:

Was ist Spiel? Warum ist sie?

Spielen ist ein Schlüsselelement für ein Playbook, da „Spielen“ und „nur Spielen“ eine Liste von Rollen und/oder Aufgaben mit einer Liste von Hosts verknüpft, auf denen sie ausgeführt werden müssen. In den Tiefen der Dokumentation finden Sie Erwähnungen von delegate_to, lokale Lookup-Plugins, Netzwerk-CLI-spezifische Einstellungen, Jump-Hosts usw. Sie ermöglichen es Ihnen, den Ort, an dem Aufgaben ausgeführt werden, leicht zu ändern. Aber vergessen Sie es. Jede dieser cleveren Optionen hat sehr spezifische Verwendungsmöglichkeiten und ist definitiv nicht universell. Und wir sprechen über grundlegende Dinge, die jeder kennen und nutzen sollte.

Wenn Sie „irgendetwas“ „irgendwo“ aufführen möchten, schreiben Sie ein Theaterstück. Keine Rolle. Keine Rolle mit Modulen und Delegierten. Du nimmst es und schreibst ein Stück. Dabei geben Sie im Feld „Hosts“ an, wo ausgeführt werden soll, und in Rollen/Aufgaben – was ausgeführt werden soll.

Ganz einfach, oder? Wie könnte es anders sein?

Einer der charakteristischen Momente, in denen Menschen den Wunsch verspüren, dies nicht spielerisch zu tun, ist die „Rolle, die alles regelt“. Ich hätte gerne eine Rolle, die sowohl Server des ersten Typs als auch Server des zweiten Typs konfiguriert.

Ein archetypisches Beispiel ist die Überwachung. Ich hätte gerne eine Überwachungsrolle, die die Überwachung konfiguriert. Die Überwachungsrolle wird Überwachungshosts zugewiesen (je nach Spiel). Es stellt sich jedoch heraus, dass wir zur Überwachung Pakete an die Hosts liefern müssen, die wir überwachen. Warum nicht Delegat verwenden? Sie müssen auch iptables konfigurieren. delegieren? Sie müssen außerdem eine Konfiguration für das DBMS schreiben/korrigieren, um die Überwachung zu aktivieren. delegieren! Und wenn es an Kreativität mangelt, können Sie eine Delegation machen include_role in einer verschachtelten Schleife unter Verwendung eines kniffligen Filters für eine Liste von Gruppen und innerhalb include_role Du kannst mehr tun delegate_to wieder. Und weg gehen wir...

Der gute Wunsch – eine einzige Überwachungsrolle zu haben, die „alles macht“ – führt uns in die Hölle, aus der es oft nur einen Ausweg gibt: alles von Grund auf neu zu schreiben.

Wo ist hier der Fehler passiert? In dem Moment, als Sie herausgefunden haben, dass Sie zum Ausführen der Aufgabe „x“ auf Host Fügen Sie nichts zu „x“ hinzu, sondern schreiben Sie es von Grund auf neu. Auch mit hartcodierten Variablen.

Es scheint, dass in den obigen Absätzen alles richtig gesagt ist. Aber das ist nicht Ihr Fall! Weil Sie wiederverwendbaren Code schreiben möchten, der trocken und bibliotheksähnlich ist, und Sie müssen nach einer Methode dafür suchen.

Hier lauert ein weiterer schwerwiegender Fehler. Ein Fehler, der viele Projekte von einigermaßen geschriebenen Projekten (es könnte besser sein, aber alles funktioniert und ist leicht zu beenden) in einen völligen Horror verwandelt hat, den selbst der Autor nicht verstehen kann. Es funktioniert, aber Gott bewahre, dass du irgendetwas änderst.

Der Fehler ist: Rolle ist eine Bibliotheksfunktion. Diese Analogie hat so viele gute Anfänge ruiniert, dass es einfach traurig ist, dabei zuzusehen. Die Rolle ist keine Bibliotheksfunktion. Sie kann weder rechnen noch spielerische Entscheidungen treffen. Erinnern Sie mich daran, welche Entscheidungen das Spiel trifft?

Danke, du hast recht. Play trifft eine Entscheidung (genauer gesagt, es enthält Informationen) darüber, welche Aufgaben und Rollen auf welchen Hosts ausgeführt werden sollen.

Wenn Sie diese Entscheidung an eine Rolle delegieren und sogar mit Berechnungen, verurteilen Sie sich selbst (und denjenigen, der versucht, Ihren Code zu analysieren) zu einer miserablen Existenz. Die Rolle entscheidet nicht darüber, wo sie ausgeübt wird. Diese Entscheidung wird spielerisch getroffen. Die Rolle tut, was ihr gesagt wird, und zwar dort, wo sie gesagt wird.

Warum es gefährlich ist, in Ansible zu programmieren und warum COBOL besser als Ansible ist, werden wir im Kapitel über Variablen und Jinja besprechen. Sagen wir vorerst eines: Jede Ihrer Berechnungen hinterlässt eine unauslöschliche Spur von Änderungen globaler Variablen, und Sie können nichts dagegen tun. Sobald sich die beiden „Spuren“ kreuzten, war alles verschwunden.

Hinweis für Zimperliche: Die Rolle kann durchaus Einfluss auf den Kontrollfluss haben. Essen delegate_to und es hat vernünftige Verwendungsmöglichkeiten. Essen meta: end host/play. Aber! Denken Sie daran, dass wir die Grundlagen vermitteln? Vergessen delegate_to. Wir sprechen über den einfachsten und schönsten Ansible-Code. Das ist leicht zu lesen, leicht zu schreiben, leicht zu debuggen, leicht zu testen und leicht zu vervollständigen. Also noch einmal:

Play und nur Play entscheidet darüber, auf welchem ​​Host was ausgeführt wird.

In diesem Abschnitt haben wir uns mit dem Gegensatz zwischen Spiel und Rolle beschäftigt. Lassen Sie uns nun über die Beziehung zwischen Aufgaben und Rollen sprechen.

Aufgaben und Rollen

Betrachten Sie das Spiel:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

Nehmen wir an, Sie müssen foo tun. Und es sieht so aus foo: name=foobar state=present. Wo soll ich das schreiben? im Vorfeld? Post? Eine Rolle erstellen?

...Und wo sind die Aufgaben geblieben?

Wir beginnen wieder mit dem Wesentlichen – dem Spielgerät. Wenn Sie bei diesem Thema schwanken, können Sie das Spiel nicht als Grundlage für alles andere verwenden, und Ihr Ergebnis wird „wackelig“ sein.

Play-Gerät: Hosts-Direktive, Einstellungen für Play selbst und pre_tasks, Aufgaben, Rollen, post_tasks-Abschnitte. Die restlichen Spielparameter sind für uns jetzt nicht wichtig.

Die Reihenfolge ihrer Abschnitte mit Aufgaben und Rollen: pre_tasks, roles, tasks, post_tasks. Da die Reihenfolge der Ausführung semantisch zwischen liegt tasks и roles nicht klar ist, dann sagen Best Practices, dass wir einen Abschnitt hinzufügen tasks, nur wenn nicht roles. Wenn es gibt roles, dann werden alle angehängten Aufgaben in Abschnitte eingeordnet pre_tasks/post_tasks.

Bleibt nur noch, dass alles semantisch klar ist: erstens pre_tasksdann rolesdann post_tasks.

Aber wir haben die Frage immer noch nicht beantwortet: Wo ist der Modulaufruf? foo schreiben? Müssen wir für jedes Modul eine ganze Rolle schreiben? Oder ist es besser, für alles eine dicke Rolle zu haben? Und wenn es keine Rolle ist, wo soll ich dann schreiben – im Vorfeld oder im Nachhinein?

Wenn es auf diese Fragen keine begründete Antwort gibt, dann ist das ein Zeichen mangelnder Intuition, also eben dieser „wackeligen Grundlagen“. Lass es uns herausfinden. Zunächst eine Sicherheitsfrage: Ob gespielt wird pre_tasks и post_tasks (und es gibt keine Aufgaben oder Rollen), dann kann etwas kaputt gehen, wenn ich die erste Aufgabe ausführe post_tasks Ich verschiebe es ans Ende pre_tasks?

Natürlich deutet der Wortlaut der Frage darauf hin, dass es kaputt gehen wird. Aber was genau?

... Handler. Das Lesen der Grundlagen offenbart eine wichtige Tatsache: Alle Handler werden nach jedem Abschnitt automatisch geleert. Diese. alle Aufgaben aus pre_tasks, dann alle Handler, die benachrichtigt wurden. Anschließend werden alle Rollen und alle in den Rollen benachrichtigten Handler ausgeführt. Nach post_tasks und ihre Betreuer.

Wenn Sie also eine Aufgabe aus ziehen post_tasks в pre_tasks, dann führen Sie es möglicherweise aus, bevor der Handler ausgeführt wird. zum Beispiel, wenn in pre_tasks der Webserver installiert und konfiguriert ist und post_tasks etwas wird an ihn gesendet, dann übertragen Sie diese Aufgabe an den Abschnitt pre_tasks führt dazu, dass zum Zeitpunkt des „Sendens“ der Server noch nicht läuft und alles kaputt geht.

Denken wir jetzt noch einmal darüber nach, warum wir es brauchen pre_tasks и post_tasks? Zum Beispiel, um vor der Erfüllung der Rolle alles Notwendige zu erledigen (einschließlich Handler). A post_tasks ermöglicht es uns, mit den Ergebnissen der Ausführung von Rollen (einschließlich Handlern) zu arbeiten.

Ein kluger Ansible-Experte wird uns sagen, was es ist. meta: flush_handlers, aber warum brauchen wir Flush_handlers, wenn wir uns auf die Ausführungsreihenfolge der im Spiel befindlichen Abschnitte verlassen können? Darüber hinaus kann die Verwendung von meta:flush_handlers zu unerwarteten Dingen mit doppelten Handlern führen und uns bei der Verwendung seltsame Warnungen auslösen when у block usw. Je besser Sie das Ansible kennen, desto mehr Nuancen können Sie für eine „knifflige“ Lösung benennen. Und eine einfache Lösung – die Verwendung einer natürlichen Aufteilung zwischen Vor/Rollen/Post – führt nicht zu Nuancen.

Und zurück zu unserem „Foo“. Wo soll ich es hinstellen? Im Vorfeld, im Nachhinein oder in den Rollen? Dies hängt natürlich davon ab, ob wir die Ergebnisse des Handlers für foo benötigen. Wenn sie nicht vorhanden sind, muss foo weder im Pre- noch im Post-Bereich platziert werden – diese Abschnitte haben eine besondere Bedeutung – sie führen Aufgaben vor und nach dem Hauptteil des Codes aus.

Die Antwort auf die Frage „Rolle oder Aufgabe“ kommt nun darauf an, was bereits im Spiel ist – wenn dort Aufgaben vorhanden sind, müssen Sie diese zu Aufgaben hinzufügen. Wenn Rollen vorhanden sind, müssen Sie eine Rolle erstellen (auch aus einer Aufgabe). Ich möchte Sie daran erinnern, dass Aufgaben und Rollen nicht gleichzeitig verwendet werden.

Das Verständnis der Grundlagen von Ansible liefert vernünftige Antworten auf scheinbar Geschmacksfragen.

Aufgaben und Rollen (Teil zwei)

Lassen Sie uns nun die Situation besprechen, in der Sie gerade erst anfangen, ein Playbook zu schreiben. Sie müssen Foo, Bar und Baz zubereiten. Sind das drei Aufgaben, eine Rolle oder drei Rollen? Um die Frage zusammenzufassen: Ab wann sollte man mit dem Schreiben von Rollen beginnen? Was bringt es, Rollen zu schreiben, wenn man Aufgaben schreiben kann? ... Was ist eine Rolle?

Einer der größten Fehler (darüber habe ich bereits gesprochen) besteht darin, zu glauben, eine Rolle sei wie eine Funktion in der Bibliothek eines Programms. Wie sieht eine generische Funktionsbeschreibung aus? Es akzeptiert Eingabeargumente, interagiert mit Nebenursachen, führt Nebenwirkungen aus und gibt einen Wert zurück.

Nun, Achtung. Was kann daraus in der Rolle gemacht werden? Sie können jederzeit gerne Nebenwirkungen nennen, das ist die Essenz des gesamten Ansible – Nebenwirkungen zu erzeugen. Gibt es Nebenursachen? Grundschule. Aber mit „Wert übergeben und zurückgeben“ funktioniert das nicht. Erstens können Sie keinen Wert an eine Rolle übergeben. Sie können im Abschnitt „Vars“ für die Rolle eine globale Variable mit einer lebenslangen Spieldauer festlegen. Sie können innerhalb der Rolle eine globale Variable mit einer Lebensdauer festlegen. Oder sogar mit der Lebensdauer von Playbooks (set_fact/register). Aber Sie können keine „lokalen Variablen“ haben. Sie können nicht „einen Wert nehmen“ und ihn „zurückgeben“.

Daraus folgt die Hauptsache: Man kann in Ansible nichts schreiben, ohne Nebenwirkungen zu verursachen. Das Ändern globaler Variablen ist bei einer Funktion immer ein Nebeneffekt. In Rust beispielsweise ist das Ändern einer globalen Variablen unsafe. Und in Ansible ist es die einzige Methode, die Werte für eine Rolle zu beeinflussen. Beachten Sie die verwendeten Wörter: nicht „einen Wert an die Rolle übergeben“, sondern „die von der Rolle verwendeten Werte ändern“. Es gibt keine Isolation zwischen den Rollen. Es gibt keine Trennung zwischen Aufgaben und Rollen.

Total: Eine Rolle ist keine Funktion.

Was ist das Gute an der Rolle? Erstens verfügt die Rolle über Standardwerte (/default/main.yaml), zweitens verfügt die Rolle über zusätzliche Verzeichnisse zum Speichern von Dateien.

Welche Vorteile bieten Standardwerte? Denn in Maslows Pyramide, Ansibles eher verzerrter Tabelle variabler Prioritäten, haben Rollenstandards die niedrigste Priorität (abzüglich Ansible-Befehlszeilenparameter). Das heißt, wenn Sie Standardwerte bereitstellen müssen und sich keine Sorgen machen müssen, dass diese die Werte aus Inventar- oder Gruppenvariablen überschreiben, dann sind Rollenstandards der einzig richtige Ort für Sie. (Ich lüge ein wenig – es gibt noch mehr |d(your_default_here), aber wenn wir über stationäre Orte sprechen, dann nur Rollenvorgaben).

Was ist sonst noch toll an den Rollen? Weil sie ihre eigenen Kataloge haben. Dies sind Verzeichnisse für Variablen, sowohl konstante (d. h. für die Rolle berechnete) als auch dynamische (es gibt entweder ein Muster oder ein Anti-Muster - include_vars mit {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml.). Dies sind die Verzeichnisse für files/, templates/. Außerdem können Sie Ihre eigenen Module und Plugins verwenden (library/). Aber im Vergleich zu Aufgaben in einem Playbook (das alles auch haben kann) besteht der einzige Vorteil hier darin, dass die Dateien nicht auf einem Stapel, sondern in mehreren separaten Stapeln abgelegt werden.

Noch ein Detail: Sie können versuchen, Rollen zu erstellen, die zur Wiederverwendung verfügbar sind (über Galaxy). Mit dem Aufkommen von Sammlungen kann die Rollenverteilung als nahezu vergessen betrachtet werden.

Daher verfügen Rollen über zwei wichtige Merkmale: Sie verfügen über Standardwerte (ein einzigartiges Merkmal) und ermöglichen Ihnen die Strukturierung Ihres Codes.

Zurück zur ursprünglichen Frage: Wann sind Aufgaben zu erledigen und wann sind Rollen zu übernehmen? Aufgaben in einem Playbook werden am häufigsten entweder als „Kleber“ vor/nach Rollen oder als unabhängiges Bauelement verwendet (dann sollte es keine Rollen im Code geben). Ein Haufen normaler Aufgaben gemischt mit Rollen ist eindeutig Schlamperei. Sie sollten sich an einen bestimmten Stil halten – entweder eine Aufgabe oder eine Rolle. Rollen sorgen für die Trennung von Entitäten und Standardwerten, Aufgaben ermöglichen Ihnen ein schnelleres Lesen von Code. Normalerweise wird eher „stationärer“ (wichtiger und komplexer) Code in Rollen gepackt und Hilfsskripte im Task-Stil geschrieben.

Es ist möglich, import_role als Aufgabe auszuführen, aber wenn Sie dies schreiben, müssen Sie darauf vorbereitet sein, Ihrem eigenen Sinn für Schönheit zu erklären, warum Sie dies tun möchten.

Ein scharfsinniger Leser könnte sagen, dass Rollen Rollen importieren können, Rollen Abhängigkeiten über galaxy.yml haben können und es auch ein schreckliches und schreckliches gibt include_role — Ich erinnere Sie daran, dass wir die Fähigkeiten im grundlegenden Ansible verbessern und nicht im Figurenturnen.

Handler und Aufgaben

Lassen Sie uns eine weitere offensichtliche Sache besprechen: Handler. Zu wissen, wie man sie richtig einsetzt, ist fast eine Kunst. Was ist der Unterschied zwischen einem Handler und einem Drag?

Da wir uns an die Grundlagen erinnern, hier ein Beispiel:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

Die Handler der Rolle befinden sich in Rolename/handlers/main.yaml. Handler stöbern zwischen allen Spielteilnehmern: pre/post_tasks können Rollenhandler ziehen, und eine Rolle kann Handler aus dem Spiel ziehen. Allerdings verursachen „rollenübergreifende“ Aufrufe von Handlern viel mehr Ärger als die Wiederholung eines trivialen Handlers. (Ein weiteres Element der Best Practices besteht darin, zu versuchen, Handlernamen nicht zu wiederholen.)

Der Hauptunterschied besteht darin, dass die Aufgabe immer (idempotent) ausgeführt wird (Plus/Minus-Tags und when) und der Handler – nach Statusänderung (Benachrichtigung wird nur ausgelöst, wenn sie geändert wurde). Was bedeutet das? Zum Beispiel die Tatsache, dass beim Neustart kein Handler vorhanden ist, wenn keine Änderungen vorgenommen wurden. Warum kann es sein, dass wir den Handler ausführen müssen, wenn sich an der Generierungsaufgabe nichts geändert hat? Zum Beispiel, weil etwas kaputt gegangen ist und sich verändert hat, die Ausführung aber nicht beim Handler angekommen ist. Zum Beispiel, weil das Netzwerk vorübergehend ausgefallen war. Die Konfiguration hat sich geändert, der Dienst wurde nicht neu gestartet. Beim nächsten Start ändert sich die Konfiguration nicht mehr und der Dienst verbleibt bei der alten Version der Konfiguration.

Die Situation mit der Konfiguration kann nicht gelöst werden (genauer gesagt, Sie können sich ein spezielles Neustartprotokoll mit Dateiflags usw. ausdenken, aber dies ist in keiner Form mehr „grundlegend ansible“). Aber es gibt noch eine andere gemeinsame Geschichte: Wir haben die Anwendung installiert und aufgezeichnet .service-Datei, und jetzt wollen wir es daemon_reload и state=started. Und der natürliche Ort dafür scheint der Hundeführer zu sein. Wenn Sie es jedoch nicht zu einem Handler, sondern zu einer Aufgabe am Ende einer Aufgabenliste oder Rolle machen, wird es jedes Mal idempotent ausgeführt. Auch wenn das Spielbuch mittendrin kaputt ging. Dies löst das Problem „restarted“ überhaupt nicht (Sie können keine Aufgabe mit dem Attribut „restarted“ ausführen, da die Idempotenz verloren geht), aber es lohnt sich auf jeden Fall, „state=started“ auszuführen, da sich die Gesamtstabilität von Playbooks erhöht, weil die Anzahl der Verbindungen und der dynamische Zustand nehmen ab.

Eine weitere positive Eigenschaft des Handlers ist, dass er die Ausgabe nicht verstopft. Es gab keine Änderungen – keine zusätzlichen Übersprungen oder OK in der Ausgabe – einfacher zu lesen. Es ist auch eine negative Eigenschaft – wenn Sie beim ersten Durchlauf in einer linear ausgeführten Aufgabe einen Tippfehler finden, werden die Handler nur ausgeführt, wenn sie geändert werden, d. h. unter bestimmten Bedingungen - sehr selten. Zum Beispiel zum ersten Mal in meinem Leben fünf Jahre später. Und natürlich gibt es einen Tippfehler im Namen und alles geht kaputt. Und wenn Sie sie nicht ein zweites Mal ausführen, ändert sich nichts.

Unabhängig davon müssen wir über die Verfügbarkeit von Variablen sprechen. Wenn Sie beispielsweise eine Aufgabe mit einer Schleife benachrichtigen, was steht dann in den Variablen? Sie können analytisch raten, aber das ist nicht immer trivial, insbesondere wenn die Variablen von verschiedenen Orten stammen.

... Handler sind also viel weniger nützlich und viel problematischer, als sie scheinen. Wenn Sie etwas Schönes (ohne Schnickschnack) ohne Handler schreiben können, ist es besser, es ohne Handler zu tun. Wenn es nicht so gut klappt, ist es besser bei ihnen.

Der ätzende Leser weist zu Recht darauf hin, dass wir nicht darüber gesprochen haben listendass ein Handler notify für einen anderen Handler aufrufen kann, dass ein Handler import_tasks einschließen kann (was include_role mit with_items tun kann), dass das Handlersystem in Ansible Turing-vollständig ist, dass sich Handler aus include_role auf seltsame Weise mit Handlern aus play überschneiden, usw. .d. - All dies ist eindeutig nicht die „Grundlagen“).

Allerdings gibt es eine bestimmte WTF-Funktion, die Sie unbedingt im Hinterkopf behalten sollten. Wenn Ihre Aufgabe mit ausgeführt wird delegate_to und es hat notify, dann wird der entsprechende Handler ohne ausgeführt delegate_to, d.h. auf dem Host, dem die Wiedergabe zugewiesen ist. (Obwohl der Handler das natürlich auch getan hat delegate_to Dasselbe).

Separat möchte ich ein paar Worte zu wiederverwendbaren Rollen sagen. Bevor Kollektionen erschienen, gab es die Idee, universelle Rollen zu schaffen, die sein könnten ansible-galaxy install und ging. Funktioniert auf allen Betriebssystemen aller Varianten in allen Situationen. Also meine Meinung: Es funktioniert nicht. Jede Rolle mit Masse include_vars, das 100500 Fälle unterstützt, ist dazu verdammt, einen Abgrund von Eckfallfehlern zu beseitigen. Sie können mit umfangreichen Tests abgedeckt werden, aber wie bei jedem Test haben Sie entweder ein kartesisches Produkt aus Eingabewerten und einer Gesamtfunktion oder Sie haben „einzelne Szenarien abgedeckt“. Meiner Meinung nach ist es viel besser, wenn die Rolle linear ist (zyklomatische Komplexität 1).

Je weniger Wenns (explizit oder deklarativ – in der Form when oder Form include_vars je nach Satz von Variablen), desto besser ist die Rolle. Manchmal muss man Zweige machen, aber ich wiederhole: Je weniger, desto besser. Es scheint also eine gute Rolle bei Galaxy zu sein (es funktioniert!) mit einer Menge when ist möglicherweise weniger vorzuziehen als die „eigene“ Rolle aus fünf Aufgaben. Der Moment, in dem die Rolle bei Galaxy besser ist, ist, wenn man anfängt, etwas zu schreiben. Der Moment, in dem es schlimmer wird, ist, wenn etwas kaputt geht und Sie den Verdacht haben, dass es an der „Rolle mit der Galaxie“ liegt. Man öffnet es und findet dort fünf Beilagen, acht Aufgabenblätter und einen Stapel when'ov... Und wir müssen das herausfinden. Statt 5 Aufgaben eine lineare Liste, in der es nichts zu brechen gibt.

In den folgenden Teilen

  • Ein wenig über Inventar, Gruppenvariablen, host_group_vars-Plugin, Hostvars. Wie man mit Spaghetti einen Gordischen Knoten bindet. Umfangs- und Prioritätsvariablen, Ansible-Speichermodell. „Wo speichern wir also den Benutzernamen für die Datenbank?“
  • jinja: {{ jinja }} — Nosql NoType Nosense weiches Plastilin. Es ist überall, auch dort, wo man es nicht erwartet. Ein bisschen darüber !!unsafe und leckeres Yaml.

Source: habr.com

Kommentar hinzufügen