Ab dem zweiten Commit wird jeder Code zum Legacy, weil Die anfänglichen Vorstellungen beginnen von der harten Realität abzuweichen. Das ist weder gut noch schlecht, es ist eine Tatsache, mit der man nur schwer streiten kann und mit der man leben muss. Ein Teil dieses Prozesses ist das Refactoring. Refactoring der Infrastruktur als Code. Beginnen wir mit der Geschichte, wie man Ansible in einem Jahr umgestalten kann, ohne verrückt zu werden.
Die Geburt des Vermächtnisses
Tag Nr. 1: Patient Null
Es war einmal ein bedingtes Projekt. Es gab ein Dev-Entwicklungsteam und Ops-Ingenieure. Sie lösten das gleiche Problem: wie man Server bereitstellt und eine Anwendung ausführt. Das Problem bestand darin, dass jedes Team dieses Problem auf seine eigene Weise löste. Im Rahmen des Projekts wurde beschlossen, Ansible zu verwenden, um das Wissen zwischen den Dev- und Ops-Teams zu synchronisieren.
Tag Nr. 89: Die Geburt von Legacy
Ohne es selbst zu merken, wollten sie es so gut wie möglich machen, doch es stellte sich als Vermächtnis heraus. Wie kommt es dazu?
Wir haben hier eine dringende Aufgabe. Lasst uns einen Dirty Hack durchführen und das Problem dann beheben.
Sie müssen keine Dokumentation schreiben und alles ist klar, was hier vor sich geht.
Ich kenne Ansible/Python/Bash/Terraform! Schau, wie ich ausweichen kann!
Ich bin ein Full-Stack-Overflow-Entwickler und habe dies von Stackoverflow kopiert. Ich weiß nicht, wie es funktioniert, aber es sieht cool aus und löst das Problem.
Infolgedessen erhalten Sie möglicherweise einen unverständlichen Codetyp, für den es keine Dokumentation gibt. Es ist nicht klar, was er tut und ob er benötigt wird. Das Problem besteht jedoch darin, dass Sie ihn entwickeln, ändern und Krücken und Unterstützungen hinzufügen müssen , was die Situation noch schlimmer macht.
Das ursprünglich konzipierte und implementierte IaC-Modell entspricht nicht mehr den Anforderungen von Benutzern / Unternehmen / anderen Teams und die Zeit für Änderungen an der Infrastruktur ist nicht mehr akzeptabel. In diesem Moment kommt die Erkenntnis, dass es an der Zeit ist, Maßnahmen zu ergreifen.
IaC-Refactoring
Tag Nr. 139: Brauchen Sie wirklich ein Refactoring?
Bevor Sie mit der Umgestaltung beginnen, müssen Sie eine Reihe wichtiger Fragen beantworten:
Warum brauchst du das alles?
Habt ihr Zeit?
Reicht Wissen?
Wenn Sie nicht wissen, wie Sie die Fragen beantworten sollen, endet das Refactoring, bevor es überhaupt begonnen hat, oder es wird möglicherweise nur noch schlimmer. Weil hatte Erfahrung( Was ich aus dem Testen von 200 Zeilen Infrastrukturcode gelernt habe), dann erhielt das Projekt eine Bitte um Hilfe bei der Festlegung der Rollen und deren Abdeckung durch Tests.
Tag Nr. 149: Vorbereitung des Refactorings
Das Erste ist die Vorbereitung. Entscheiden Sie, was wir tun werden. Dazu kommunizieren wir, finden Problembereiche und finden Lösungsansätze. Wir halten die resultierenden Konzepte irgendwie fest, zum Beispiel einen Artikel in Confluence, sodass wir bei der Frage „Was ist das Beste?“ aufzeichnen können. oder „Was ist richtig?“ Wir haben uns nicht verirrt. In unserem Fall sind wir bei der Idee geblieben Teile und herrsche: Wir zerlegen die Infrastruktur in kleine Stücke/Steine. Dieser Ansatz ermöglicht es Ihnen, ein isoliertes Stück Infrastruktur zu nehmen, zu verstehen, was es tut, es mit Tests abzudecken und es zu ändern, ohne befürchten zu müssen, dass etwas kaputt geht.
Es stellt sich heraus, dass Infrastrukturtests zum Grundstein werden und hier ist die Infrastrukturtestpyramide erwähnenswert. Genau die gleiche Idee, die sich in der Entwicklung befindet, aber für die Infrastruktur: Wir bewegen uns von billigen Schnelltests, die einfache Dinge wie Einrückungen überprüfen, zu teuren, vollwertigen Tests, die die gesamte Infrastruktur bereitstellen.
Ansible-Testversuche
Bevor wir beschreiben, wie wir Ansible-Tests im Projekt durchgeführt haben, werde ich die Versuche und Ansätze beschreiben, die ich zuvor nutzen konnte, um den Kontext der getroffenen Entscheidungen zu verstehen.
Tag Nr. -997: SDS-Bereitstellung
Das erste Mal, dass ich Ansible getestet habe, war bei einem Projekt zur Entwicklung von SDS (Software Defined Storage). Zu diesem Thema gibt es einen separaten Artikel So brechen Sie beim Testen Ihrer Distribution Fahrräder über Krücken, aber kurz gesagt, am Ende hatten wir eine umgekehrte Testpyramide und haben 60 bis 90 Minuten mit dem Testen einer Rolle verbracht, was eine lange Zeit ist. Grundlage waren e2e-Tests, d.h. Wir haben eine vollständige Installation bereitgestellt und diese dann getestet. Noch ärgerlicher war die Erfindung seines eigenen Fahrrads. Aber ich muss zugeben, dass diese Lösung funktionierte und eine stabile Veröffentlichung ermöglichte.
Tag # -701: Ansible und Testküche
Die Entwicklung der Ansible-Testidee bestand in der Verwendung vorgefertigter Tools, nämlich test kitchen / kitchen-ci und inspec. Die Wahl wurde durch Kenntnisse über Ruby bestimmt (weitere Einzelheiten finden Sie im Artikel über Habré: Träumen YML-Programmierer davon, Ansible zu testen?) arbeitete schneller, etwa 40 Minuten für 10 Rollen. Wir haben ein Paket virtueller Maschinen erstellt und darin Tests durchgeführt.
Im Allgemeinen funktionierte die Lösung, es gab jedoch aufgrund der Heterogenität etwas Sediment. Als die Anzahl der getesteten Personen auf 13 Basisrollen und 2 Metarollen, die kleinere Rollen kombinieren, erhöht wurde, begannen die Tests plötzlich mit einer Laufzeit von 70 Minuten, was fast dem Doppelten entspricht. Es war schwierig, über XP-Praktiken (extreme Programmierung) zu sprechen, weil ... Niemand möchte 2 Minuten warten. Dies war der Grund für die Änderung des Ansatzes
Tag # -601: Ansible und Molekül
Vom Konzept her ähnelt dies testkitchen, nur haben wir das Rollentesten auf Docker verschoben und den Stack geändert. Dadurch konnte die Zeit für 20 Rollen auf stabile 25-7 Minuten verkürzt werden.
Indem wir die Anzahl der getesteten Rollen auf 17 erhöhten und 45 Rollen reduzierten, führten wir dies in 28 Minuten auf 2 Jenkins-Slaves aus.
Tag Nr. 167: Ansible-Tests zum Projekt hinzufügen
Höchstwahrscheinlich wird es nicht möglich sein, die Refactoring-Aufgabe so schnell durchzuführen. Die Aufgabe muss messbar sein, sodass man sie in kleine Stücke zerbrechen und den Elefanten Stück für Stück mit einem Teelöffel essen kann. Es muss ein Verständnis dafür vorhanden sein, ob Sie sich in die richtige Richtung bewegen und wie lange es noch dauern wird.
Im Allgemeinen spielt es keine Rolle, wie es gemacht wird, Sie können auf ein Blatt Papier schreiben, Aufkleber auf den Schrank kleben, Aufgaben in Jira erstellen oder Google Docs öffnen und den aktuellen Status notieren Dort. Die Beine wachsen dadurch, dass der Prozess nicht sofort erfolgt, er wird langwierig und mühsam sein. Es ist unwahrscheinlich, dass irgendjemand möchte, dass Ihnen beim Refactoring die Ideen ausgehen, Sie müde werden und überfordert sind.
Das Refactoring ist einfach:
Essen.
Schlafen.
Code.
IaC-Test.
Wiederholen
und wir wiederholen dies, bis wir das beabsichtigte Ziel erreichen.
Da es möglicherweise nicht möglich ist, sofort mit dem Testen zu beginnen, bestand unsere erste Aufgabe darin, mit dem Linting und der Überprüfung der Syntax zu beginnen.
Tag Nr. 181: Green Build Master
Linting ist ein kleiner erster Schritt in Richtung Green Build Master. Dadurch wird fast nichts kaputt gehen, aber es ermöglicht Ihnen, Prozesse zu debuggen und umweltfreundliche Builds in Jenkins zu erstellen. Die Idee besteht darin, Gewohnheiten im Team zu entwickeln:
Rote Tests sind schlecht.
Ich bin gekommen, um etwas zu reparieren und gleichzeitig den Code etwas besser zu machen als vor Ihnen.
Tag Nr. 193: Vom Flusen zum Unit-Test
Nachdem Sie den Prozess zum Einspielen des Codes in den Master erstellt haben, können Sie mit dem Prozess der schrittweisen Verbesserung beginnen – indem Sie Linting durch das Starten von Rollen ersetzen, können Sie dies sogar ohne Idempotenz tun. Sie müssen verstehen, wie Rollen angewendet werden und wie sie funktionieren.
Tag Nr. 211: Von Unit- zu Integrationstests
Wenn die meisten Rollen mit Unit-Tests abgedeckt sind und alles ausgefranst ist, können Sie mit dem Hinzufügen von Integrationstests fortfahren. Diese. Testen Sie nicht einen einzelnen Baustein in der Infrastruktur, sondern eine Kombination davon, beispielsweise eine vollständige Instanzkonfiguration.
Mit Jenkins haben wir viele Phasen generiert, in denen Rollen/Playbooks parallel verteilt wurden, dann Unit-Tests in Containern und schließlich Integrationstests.
Jenkins + Docker + Ansible = Tests
Checken Sie das Repo aus und generieren Sie Build-Phasen.
Führen Sie Lint-Playbook-Stufen parallel aus.
Führen Sie Lint-Roll-Phasen parallel aus.
Führen Sie die Rollenphasen der Syntaxprüfung parallel aus.
Führen Sie Testrollenphasen parallel aus.
Fusselrolle.
Prüfen Sie die Abhängigkeit zu anderen Rollen.
Syntax prüfen.
Erstellen Sie eine Docker-Instanz
Führen Sie „molecular/default/playbook.yml“ aus.
Überprüfen Sie die Idempotenz.
Führen Sie Integrationstests durch
Endziel
Tag Nr. 271: Busfaktor
Das Refactoring wurde zunächst von einer kleinen Gruppe von zwei bis drei Personen durchgeführt. Sie haben den Code im Master überprüft. Im Laufe der Zeit entwickelte das Team Kenntnisse darüber, wie man Code schreibt, und die Codeüberprüfung trug zur Verbreitung von Wissen über die Infrastruktur und ihre Funktionsweise bei. Der Clou dabei war, dass die Gutachter einzeln nach einem Zeitplan ausgewählt wurden, d. h. Mit einiger Wahrscheinlichkeit werden Sie in ein neues Stück Infrastruktur aufsteigen.
Und gemütlich soll es hier sein. Es ist praktisch, eine Überprüfung durchzuführen, um zu sehen, in welchem Rahmen die Aufgabe erledigt wurde und wie die Diskussionen verlaufen sind. Wir haben Jenkins + Bitbucket + Jira integriert.
Aber als solches ist eine Rezension kein Allheilmittel; irgendwie sind wir in den Mastercode geraten, der uns dazu brachte, Tests zu scheitern:
Mit der Zeit gab es mehr Tests, Builds liefen langsamer, im schlimmsten Fall bis zu einer Stunde. Auf einer der Retros stand ein Satz wie „Es ist gut, dass es Tests gibt, aber sie sind langsam.“ Aus diesem Grund haben wir auf Integrationstests auf virtuellen Maschinen verzichtet und diese für Docker angepasst, um sie schneller zu machen. Außerdem haben wir testinfra durch Ansible Verifier ersetzt, um die Anzahl der verwendeten Tools zu reduzieren.
Genau genommen gab es eine Reihe von Maßnahmen:
Wechseln Sie zu Docker.
Entfernen Sie Rollentests, die aufgrund von Abhängigkeiten dupliziert werden.
Erhöhen Sie die Anzahl der Slaves.
Testlaufreihenfolge.
Fähigkeit zu fusseln ALL lokal mit einem Befehl.
Dadurch wurde auch Pipeline auf Jenkins vereinheitlicht
Generieren Sie Build-Stufen.
Alles parallel fusseln.
Führen Sie Testrollenphasen parallel aus.
Fertig stellen.
Lessons learned
Vermeiden Sie globale Variablen
Da Ansible globale Variablen verwendet, gibt es im Formular eine teilweise Problemumgehung private_role_vars, aber das ist kein Allheilmittel.
Lassen Sie mich Ihnen ein Beispiel geben. Lass uns haben role_a и role_b
Das Lustige daran ist, dass das Ergebnis von Playbooks von Dingen abhängt, die nicht immer offensichtlich sind, wie zum Beispiel der Reihenfolge, in der die Rollen aufgelistet sind. Leider liegt dies in der Natur von Ansible und das Beste, was man tun kann, ist, eine Art Vereinbarung zu verwenden, z. B. innerhalb einer Rolle nur die in dieser Rolle beschriebene Variable zu verwenden.
GUT: Verwenden Sie in Rollen für Variablen Variablen, denen der Rollenname vorangestellt ist. Durch die Betrachtung des Inventars wird es einfacher, zu verstehen, was passiert.
BAD: Standardvariable in Schleifen verwenden item, wenn diese Aufgabe/dieses Playbook irgendwo enthalten ist, kann dies zu unerwartetem Verhalten führen
Wir haben uns darauf geeinigt, variable Präfixe zu verwenden; es wäre nicht überflüssig zu prüfen, ob sie wie erwartet definiert sind und beispielsweise nicht durch einen leeren Wert überschrieben werden
GUT: Variablen prüfen.
- name: "Verify that required string variables are defined"
assert:
that: ahs_var is defined and ahs_var | length > 0 and ahs_var != None
fail_msg: "{{ ahs_var }} needs to be set for the role to work "
success_msg: "Required variables {{ ahs_var }} is defined"
loop_control:
loop_var: ahs_var
with_items:
- ahs_item1
- ahs_item2
- ahs_item3
Vermeiden Sie Hash-Wörterbücher und verwenden Sie eine flache Struktur
Wenn eine Rolle einen Hash/Wörterbuch in einem ihrer Parameter erwartet, müssen wir, wenn wir einen der untergeordneten Parameter ändern möchten, den gesamten Hash/Wörterbuch überschreiben, was die Konfigurationskomplexität erhöht.
Rollen und Spielbücher müssen idempotent sein, weil Reduziert Konfigurationsdrift und die Angst, etwas kaputt zu machen. Wenn Sie jedoch ein Molekül verwenden, ist dies das Standardverhalten.
Vermeiden Sie die Verwendung von Befehls-Shell-Modulen
Die Verwendung eines Shell-Moduls führt zu einem imperativen Beschreibungsparadigma anstelle des deklarativen, das den Kern von Ansible bildet.
Testen Sie Ihre Rollen per Molekül
Moleküle sind sehr flexibel, schauen wir uns einige Szenarien an.
Molekül Mehrere Instanzen
В molecule.yml im Abschnitt platforms Sie können viele Hosts beschreiben, die Sie bereitstellen können.
Im Molekül ist es möglich, mit Ansible zu überprüfen, ob die Instanz korrekt konfiguriert wurde. Dies ist außerdem seit Release 3 die Standardeinstellung. Es ist nicht so flexibel wie testinfra/inspec, aber wir können überprüfen, ob der Inhalt der Datei unseren Erwartungen entspricht:
Oder stellen Sie den Dienst bereit, warten Sie, bis er verfügbar ist, und führen Sie einen Rauchtest durch:
---
- name: Verify
hosts: solr
tasks:
- command: /blah/solr/bin/solr start -s /solr_home -p 8983 -force
- uri:
url: http://127.0.0.1:8983/solr
method: GET
status_code: 200
register: uri_result
until: uri_result is not failed
retries: 12
delay: 10
- name: Post documents to solr
command: /blah/solr/bin/post -c master /exampledocs/books.csv
Integrieren Sie komplexe Logik in Module und Plugins
Ansible befürwortet einen deklarativen Ansatz. Wenn Sie also Codeverzweigungen, Datentransformationen oder Shell-Module durchführen, wird der Code schwer zu lesen. Um dem entgegenzuwirken und es einfach verständlich zu halten, wäre es nicht überflüssig, dieser Komplexität durch die Erstellung eigener Module entgegenzuwirken.
Fassen Sie Tipps und Tricks zusammen
Vermeiden Sie globale Variablen.
Präfix-Rollenvariablen.
Schleifenkontrollvariable verwenden.
Überprüfen Sie die Eingabevariablen.
Vermeiden Sie Hash-Wörterbücher und verwenden Sie eine flache Struktur.
Erstellen Sie idempotente Playbooks und Rollen.
Vermeiden Sie die Verwendung von Befehls-Shell-Modulen.
Testen Sie Ihre Rollen per Molekül.
Integrieren Sie komplexe Logik in Module und Plugins.
Abschluss
Sie können nicht einfach die Infrastruktur eines Projekts umgestalten, selbst wenn Sie über IaC verfügen. Dies ist ein langer Prozess, der Geduld, Zeit und Wissen erfordert.
UPD1 2020.05.01 20:30 – Zur primären Profilerstellung von Playbooks, die Sie verwenden können callback_whitelist = profile_tasks um zu verstehen, was genau lange funktioniert. Dann gehen wir durch Klassiker der Ansible-Beschleunigung. Sie können auch versuchen Mitogen UPD2 2020.05.03 16:34 - Englisch-Version