Terraformer – Infrastruktur zum Programmieren

Terraformer – Infrastruktur zum Programmieren
Ich möchte Ihnen etwas über das neue CLI-Tool erzählen, das ich geschrieben habe, um ein altes Problem zu lösen.

Problem

Terraform ist seit langem ein Standard in der Devops-/Cloud-/IT-Community. Das Ding ist sehr praktisch und nützlich für den Umgang mit Infrastruktur als Code. Es gibt viele Freuden in Terraform sowie viele Gabeln, scharfe Messer und Rechen.
Mit Terraform ist es sehr komfortabel, neue Dinge zu erstellen und diese dann zu verwalten, zu ändern oder zu löschen. Was sollten diejenigen tun, die eine riesige Infrastruktur in der Cloud haben und nicht über Terraform erstellt wurden? Das Umschreiben und Neuerstellen der gesamten Cloud ist irgendwie teuer und unsicher.
Ich bin bei zwei Jobs auf dieses Problem gestoßen. Das einfachste Beispiel ist, dass alles in Form von Terraform-Dateien in Git vorliegen soll, Sie aber mehr als 2 Buckets haben und es eine Menge ist, sie von Hand in Terraform zu schreiben.
Es gibt Problem seit 2014 in Terrafom, das 2016 in der Hoffnung auf Import geschlossen wurde.

Im Allgemeinen ist alles wie auf dem Bild, nur von rechts nach links

Warnungen: Der Autor lebt nicht die Hälfte seines Lebens in Russland und schreibt wenig auf Russisch. Achten Sie auf Rechtschreibfehler.

Решения

1. Es gibt vorgefertigte und alte Lösungen für AWS Terraforming. Als ich versuchte, meine über 250 Eimer hindurchzubekommen, wurde mir klar, dass dort alles schlecht war. AWS führt seit langem viele neue Optionen ein, aber Terraforming kennt sie nicht und ist im Allgemeinen Ruby Die Vorlage sieht spärlich aus. Nach 2 Uhr abends habe ich abgeschickt Anfrage ziehen Ich wollte dort weitere Funktionen hinzufügen und stellte fest, dass eine solche Lösung überhaupt nicht geeignet ist.
So funktioniert Terraforming: Es übernimmt Daten aus dem AWS SDK und generiert tf und tfstate über eine Vorlage.
Hier gibt es 3 Probleme:
1. Es wird immer eine Verzögerung bei Updates geben
2. TF-Dateien sind manchmal kaputt
3. tfstate wird getrennt von tf erfasst und konvergiert nicht immer
Im Allgemeinen ist es schwierig, ein Ergebnis zu erhalten, bei dem „Terraform Plan“ sagt, dass es keine Änderungen gibt

2. „Terraform Import“ ist ein in Terraform integrierter Befehl. Wie funktioniert es?
Sie schreiben eine leere TF-Datei mit dem Namen und Typ der Ressource, führen dann „terraform import“ aus und übergeben die Ressourcen-ID. Terraform kontaktiert den Anbieter, empfängt die Daten und erstellt eine tfstate-Datei.
Hier gibt es 3 Probleme:
1. Wir erhalten nur eine TFState-Datei und die TF ist leer. Sie müssen sie manuell schreiben oder aus TFState konvertieren
2. Kann jeweils nur mit einer Ressource arbeiten und unterstützt nicht alle Ressourcen. Und was soll ich bei mehr als 250 Eimern nochmal machen?
3. Sie müssen die ID der Ressourcen kennen – das heißt, Sie müssen sie in Code einbinden, der die Liste der Ressourcen abruft
Im Allgemeinen ist das Ergebnis unvollständig und lässt sich nicht gut skalieren

Meine Entscheidung

Anforderungen:
1. Möglichkeit, TF- und TFState-Dateien für Ressourcen zu erstellen. Laden Sie beispielsweise alle Buckets/Sicherheitsgruppen/Load Balancer herunter und der „Terraform-Plan“ hat zurückgegeben, dass es keine Änderungen gibt
2. Sie benötigen 2 GCP + AWS-Clouds
3. Globale Lösung, die jedes Mal einfach zu aktualisieren ist und nicht drei Arbeitstage lang Zeit für jede Ressource verschwendet
4. Machen Sie es Open Source – jeder hat das gleiche Problem

Die Go-Sprache ist der Grund, warum ich sie liebe, und sie verfügt über eine Bibliothek zum Erstellen von HCL-Dateien, die in Terraform verwendet wird, sowie eine Menge Code in Terraform, der nützlich sein kann

Weg

Erster Versuch
Ich habe mit einer einfachen Version begonnen. Kontaktieren der Cloud über das SDK für die erforderliche Ressource und Konvertieren dieser in Felder für Terraform. Der Versuch scheiterte sofort an der Sicherheitsgruppe, weil mir die 1.5 Tage, um nur die Sicherheitsgruppe zu konvertieren, nicht gefielen (und es gibt viele Ressourcen). Für eine lange Zeit und dann können Felder geändert/hinzugefügt werden

Zweiter Versuch
Basierend auf der beschriebenen Idee hier. Nehmen Sie einfach tfstate und konvertieren Sie es in tf. Alle Daten sind vorhanden und die Felder sind gleich. Wie bekomme ich den vollständigen TFState für viele Ressourcen? Hier kam der Befehl „Terraform Refresh“ zur Rettung. Terraform nimmt alle Ressourcen in tfstate und ruft anhand der ID Daten darauf ab und schreibt alles in tfstate. Das heißt, erstellen Sie einen leeren TFState nur mit Namen und IDs, führen Sie „Terraform Refresh“ aus und dann erhalten wir vollständige TFStates. Hurra!
Lassen Sie uns nun rekursiv einen Konverter für tfstate in tf schreiben. Für diejenigen, die tfstate noch nie gelesen haben: Es ist JSON, aber etwas Besonderes.
Hier sind die wichtigen Teilattribute

 "attributes": {
                            "id": "default/backend-logging-load-deployment",
                            "metadata.#": "1",
                            "metadata.0.annotations.%": "0",
                            "metadata.0.generate_name": "",
                            "metadata.0.generation": "24",
                            "metadata.0.labels.%": "1",
                            "metadata.0.labels.app": "backend-logging",
                            "metadata.0.name": "backend-logging-load-deployment",
                            "metadata.0.namespace": "default",
                            "metadata.0.resource_version": "109317427",
                            "metadata.0.self_link": "/apis/apps/v1/namespaces/default/deployments/backend-logging-load-deployment",
                            "metadata.0.uid": "300ecda1-4138-11e9-9d5d-42010a8400b5",
                            "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",

Es gibt:
1. id – Zeichenfolge
2. Metadaten – ein Array der Größe 1 und darin ein Objekt mit Feldern, die unten beschrieben werden
3. spec – Hash der Größe 1 und Schlüssel, Wert darin
Kurz gesagt, ein unterhaltsames Format, alles kann mehrere Ebenen tief sein

                   "spec.#": "1",
                            "spec.0.min_ready_seconds": "0",
                            "spec.0.paused": "false",
                            "spec.0.progress_deadline_seconds": "600",
                            "spec.0.replicas": "1",
                            "spec.0.revision_history_limit": "10",
                            "spec.0.selector.#": "1",
                            "spec.0.selector.0.match_expressions.#": "0",
                            "spec.0.selector.0.match_labels.%": "1",
                            "spec.0.selector.0.match_labels.app": "backend-logging-load",
                            "spec.0.strategy.#": "0",
                            "spec.0.template.#": "1",
                            "spec.0.template.0.metadata.#": "1",
                            "spec.0.template.0.metadata.0.annotations.%": "0",
                            "spec.0.template.0.metadata.0.generate_name": "",
                            "spec.0.template.0.metadata.0.generation": "0",
                            "spec.0.template.0.metadata.0.labels.%": "1",
                            "spec.0.template.0.metadata.0.labels.app": "backend-logging-load",
                            "spec.0.template.0.metadata.0.name": "",
                            "spec.0.template.0.metadata.0.namespace": "",
                            "spec.0.template.0.metadata.0.resource_version": "",
                            "spec.0.template.0.metadata.0.self_link": "",
                            "spec.0.template.0.metadata.0.uid": "",
                            "spec.0.template.0.spec.#": "1",
                            "spec.0.template.0.spec.0.active_deadline_seconds": "0",
                            "spec.0.template.0.spec.0.container.#": "1",
                            "spec.0.template.0.spec.0.container.0.args.#": "3",

Wenn jemand ein Programmierproblem für ein Interview haben möchte, bitten Sie ihn im Allgemeinen einfach, einen Parser für diese Aufgabe zu schreiben :)
Nach vielen Versuchen, einen Parser ohne Fehler zu schreiben, habe ich einen Teil davon im Terraform-Code gefunden, und zwar den wichtigsten Teil. Und alles schien gut zu funktionieren

Versuch drei
Terraform-Anbieter sind Binärdateien, die Code mit allen Ressourcen und der Logik für die Arbeit mit der Cloud-API enthalten. Jede Cloud hat ihren eigenen Anbieter und Terraform selbst ruft diese nur über sein RPC-Protokoll zwischen zwei Prozessen auf.
Jetzt habe ich beschlossen, Terraform-Anbieter direkt über RPC-Anrufe zu kontaktieren. Es hat wunderbar funktioniert und es ermöglicht, den Terraform-Anbieter auf neuere Anbieter umzustellen und neue Funktionen zu erhalten, ohne den Code zu ändern. Es stellt sich auch heraus, dass nicht alle Felder in tfstate in tf sein sollten, aber wie kann man das herausfinden? Fragen Sie hierzu einfach Ihren Anbieter. Dann begann eine weitere rekursive Pornographie der Zusammenstellung regulärer Ausdrücke, bei der auf allen Ebenen tiefgreifend nach Feldern innerhalb von tfstate gesucht wurde.

Am Ende haben wir ein nützliches CLI-Tool erhalten, das über eine gemeinsame Infrastruktur für alle Terraform-Anbieter verfügt und Sie problemlos eine neue hinzufügen können. Außerdem ist für das Hinzufügen von Ressourcen nur wenig Code erforderlich. Plus allerlei Extras wie Verbindungen zwischen Ressourcen. Natürlich gab es viele verschiedene Probleme, die nicht alle beschrieben werden können.
Ich habe das Tier Terrafomer genannt.

Finale

Mit Terrafomer haben wir 500–700 Zeilen tf + tfstate-Code aus zwei Clouds generiert. Wir waren in der Lage, veraltete Dinge zu übernehmen und sie nur durch Terraform zu berühren, wie in der besten Infrastruktur als Code-Ideen. Es ist einfach magisch, wenn man eine riesige Cloud nimmt und sie über ein Team in Form von Terraform-Worker-Dateien erhält. Und dann grep/replace/git und so weiter.

Ich habe es ausgekämmt und in Ordnung gebracht und die Erlaubnis erhalten. Am Donnerstag (02.05.19) auf GitHub für alle veröffentlicht. github.com/GoogleCloudPlatform/terraformer
Habe bereits 600 Sterne und 2 Pull-Anfragen zum Hinzufügen von Unterstützung für OpenStack und Kubernetes erhalten. Gute Rückmeldung. Im Allgemeinen ist das Projekt für die Menschen nützlich
Ich rate jedem, der mit Terraform arbeiten möchte, nicht alles dafür neu zu schreiben.
Gerne nehme ich Wünsche, Probleme, Sterne entgegen.

Demo
Terraformer – Infrastruktur zum Programmieren

Source: habr.com

Kommentar hinzufügen