Bei einer neuen Fluggesellschaft. Eine Stewardess betritt die Passagierkabine: „Sie sind bei unserer neuen Fluggesellschaft. Im Bug des Flugzeugs haben wir einen Kinosaal. Im Heckteil – ein Saal mit Spielautomaten. Auf dem Unterdeck – ein Schwimmbad. Auf dem Oberdeck - eine Sauna. Nun, meine Herren, schnallen Sie sich an, und mit all diesen unnötigen Dingen werden wir versuchen, abzuheben.
Hallo, mein Name ist Andrii. Ich habe die meiste Zeit meines Lebens in der IT-Branche gearbeitet. Ich interessiere mich sehr für die Entwicklung des Infrastruktur-Konfigurationsmanagement-Engineerings. Seit 8 Jahren beschäftige ich mich mit DevOps .
Einer der neuen beliebten Trends ist das Konzept von GitOps , das 2017 von Alexis Richardson, dem CEO von Weaveworks, eingeführt wurde. Weaveworks ist ein großes Unternehmen für Erwachsene, das im Jahr 2020 über 36 Millionen Euro an Investitionen für die Entwicklung seiner GitOps gesammelt hat.
In meinem vorherigen Artikel ging es um eine Erfolgsgeschichte zur Kostensenkung, wie wir von Elastic Stack zu Grafana wechselten . Jetzt werde ich versuchen, über die nicht offensichtlichen Herausforderungen zu sprechen, die bei der Übernahme dieses Konzepts auf Sie zukommen könnten. Kurz gesagt, GitOps ist keine „Silver Bullet“. Am Ende werden Sie wahrscheinlich eine Umstrukturierung mit vielen komplizierten Problemumgehungen durchführen müssen. Ich bin diesen Weg selbst gegangen und möchte Ihnen die frustrierendsten Probleme zeigen, die Sie beim Lesen anderer Artikel über GitOps nicht sehen können.
Lasst uns gleich eintauchen!
Das vielversprechendste Konzept des Infrastrukturbaus ist heute die unveränderliche Infrastruktur. Die Kernidee besteht darin, die Infrastruktur in zwei grundlegend unterschiedliche Teile zu unterteilen: zustandslos und zustandsbehaftet.
Der staatenlose Teil der Infrastruktur ist unveränderlich und idempotent. Der Status wird nicht akkumuliert (es werden keine Daten gespeichert) und die Funktionsweise wird nicht abhängig vom akkumulierten Status geändert. Instanzen des Stateless-Teils können einige grundlegende Artefakte, Skripte und Assemblys enthalten. In der Regel erstelle ich sie aus Basisimages in Cloud-/virtualisierten Umgebungen. Sie sind fragil und kurzlebig: Ich stelle neue Versionen von Anwendungen bereit, indem ich Instanzen aus neuen Basis-Images neu erstelle.
Persistente Daten werden im Stateful-Teil gespeichert. Dies kann durch das klassische Schema mit dedizierten Servern oder durch einige Cloud-Mechanismen (DBaaS, Objekt- oder Blockspeicher) realisiert werden.
Damit dieser „Zoo“ beherrschbar ist und ordnungsgemäß funktioniert, benötigen wir die Zusammenarbeit zwischen Engineering- und DevOps-Teams sowie vollständig automatisierte Lieferpipelines.
Extreme Programming ist eine der agilen Entwicklungsmethoden. Es zeichnet sich durch viele Feedbackschleifen aus, die es Ihnen ermöglichen, den Einklang mit den Bedürfnissen des Kunden zu halten.
Wir implementieren die Automatisierung von Lieferpipelines mithilfe von CI/CD-Systemen. Der Begriff CI (Continuous Integration) wurde 1994 von Grady Booch eingeführt und 1997 von Kent Beck und Ron Jeffries in die Disziplin der extremen Programmierung eingeführt. Bei CI müssen wir unsere Änderungen so oft wie möglich in den Hauptarbeitszweig unseres Projekts integrieren.
Dies erfordert zunächst eine detailliertere Aufteilung der Aufgaben: Kleine Änderungen sind atomarer und lassen sich leichter verfolgen, verstehen und integrieren. Zweitens können wir nicht einfach frisch geschriebenen Code zusammenführen. Bevor wir Zweige zusammenführen, müssen wir sicherstellen, dass nichts, was zuvor funktioniert hat, kaputt gegangen ist. Dazu sollte die Anwendung zumindest erstellt werden. Es ist auch eine gute Idee, den Code mit Tests abzudecken.
Und diese Aufgabe übernehmen CI-Systeme, die in der Entwicklung einen langen Weg zurückgelegt haben und sich irgendwo in der Mitte dieses Weges zu CI/CD-Systemen entwickelt haben.
Was ist eine CD? Martin Fowler unterscheidet zwei CD-Definitionen :
Kontinuierliche Lieferung. Dies ist der Zeitpunkt, an dem Sie mit Hilfe von Continuous-Integration-Praktiken und der DevOps-Kultur den Hauptzweig Ihres Projekts ständig für die Bereitstellung in der Produktion bereithalten.
Kontinuierliche Bereitstellung. Es handelt sich um Continuous Delivery, bei dem alles, was in den Hauptzweig gelangt, in Ihren Cluster, in Ihre Produktion, abgelegt wird.
Gehen wir weiter.
Leider weist die unveränderliche Infrastruktur mehrere Probleme auf. Der Löwenanteil davon stammt aus dem Konzept von Infrastructure as Code (IaC).
Erstens handelt es sich um eine Konfigurationsdrift. Dieser Begriff wurde in den Puppet Labs (Autoren des bekannten Puppet SCM) geboren und besagt, dass nicht alle Änderungen an Zielsystemen mit Hilfe des System Configuration Management (SCM) vorgenommen werden. Einige werden manuell ausgeführt und umgangen.
Bei solchen Mehrfachänderungen kommt es zu einer Konfigurationsdrift – dem Unterschied zwischen der im SCM beschriebenen Konfiguration und dem tatsächlichen Stand der Dinge.
Dies führt zu einer Angstspirale vor der Automatisierung.
Je mehr manuelle Änderungen vorgenommen werden, desto wahrscheinlicher ist es, dass die Ausführung eines SCM-Skripts nicht aufgezeichnete Änderungen zunichte macht. Je beängstigender es ist, es auszuführen, desto wahrscheinlicher ist es, dass neue manuelle Änderungen vorgenommen werden.
Letztendlich führt dieses bösartige positive Feedback zur Bildung von Schneeflockenservern, die so inkonsistent geworden sind, dass niemand mehr versteht, was sich darin befindet. Nach manuellen Bearbeitungen wird der Knoten so einzigartig wie jede einzelne Schneeflocke in einem Schneefall.
Durch diese Abweichung befinden sich die Server auf höheren Ebenen innerhalb einer unveränderlichen Infrastruktur: Jetzt können wir über GCP Project/AWS VPC/Kubernetes-Cluster-Snowflakes sprechen. Dies liegt daran, dass die Umsetzung von Änderungen nicht auf einer unveränderlichen Infrastruktur geregelt ist. Außerdem weiß niemand, wie man es richtig macht.
Und dann kommt Weaveworks und sagt: „Leute, wir haben, was ihr braucht – GitOps.“ Um GitOps zu fördern, holten sie ein Schwergewicht wie Kelsey Hightower, die den Leitfaden „Kubernetes auf die harte Tour“ erstellt hat. Während seiner PR verbreitet er stark die Botschaft: „Sei ein Mann, b...! Hör auf zu schreiben und fang an zu versenden.“ Und er sagt, es handele sich um ein gewisses Maß an Marketing-Bullshit-Bingo.
Meiner Meinung nach waren die aufregendsten Vorteile:
Und wer herausfinden möchte, was GitOps ist, stößt auf diese Lehrbuchfolie.
Als nächstes finden wir die GitOps-Prinzipien, die leicht erweiterten IaC-Prinzipien ähneln:
Dennoch handelt es sich hierbei um eine sphärische Beschreibung im luftleeren Raum, daher setzen wir unsere Forschung fort. Wir finden die Website GitOps.tech und darauf mehrere wichtige Klarstellungen.
Zunächst erfahren wir, dass GitOps ein infrastrukturähnlicher Code in Git mit CD-Tools ist, der diesen automatisch auf die Infrastruktur anwendet.
Wir müssen mindestens zwei Repositorys in GitOps haben:
Außerdem wird in der GitOps-Ideologie ein Pull-orientierter Ansatz einem Push-orientierten Ansatz vorgezogen. Dies steht in gewissem Widerspruch zur Entwicklung der SCM-Systeme von den schwergewichtigen Pull-Monstern Puppet und Chef zu den leichten Push-basierten Ansible und Terraform.
Und wenn GitOps in erster Linie eine Toolkit-Geschichte ist, dann ist es sinnvoll, das Flux-basierte Konzept von Weaveworks selbst zu übernehmen und es zu dekonstruieren. Die Autoren der Idee müssen eine Referenzimplementierung vorgenommen haben.
Flux ist mittlerweile auf Version 2 und besteht architektonisch aus Controllern, die innerhalb eines Clusters arbeiten:
Lassen Sie uns als Nächstes die Arbeit mit Flux und Helm besprechen.
Ich werde das Beispiel der Bereitstellung einer Anwendung mithilfe des Helm-Paketmanagers in Flux 2 weiter beschreiben.
Warum? Laut CNCF-Umfrage 2021 war der HELM-Paketmanager mit einem Anteil von mehr als 50 % die beliebteste Verpackungsanwendung.
Leider konnte ich keine aktuelleren Daten finden, aber ich glaube nicht, dass sich seitdem viel geändert hat.
Lassen Sie uns also die grundlegende Logik der Funktionsweise von Flux 2 mit Helm durchgehen. Wir haben zwei Repositorys: Anwendung und Infrastruktur.
Wir erstellen ein HELM-Chart und ein Docker-Image aus dem Anwendungs-Repository und fügen sie dem Helm-Chart-Repository bzw. der Docker-Registrierung hinzu.
Als nächstes haben wir einen Kubernetes-Cluster, auf dem die Flux-Controller ausgeführt werden.
Um unsere Anwendung bereitzustellen, bereiten wir eine YAML vor, die die benutzerdefinierte Ressource (CR) HelmRelease beschreibt, und fügen sie dem Infrastruktur-Repository hinzu.
Um Flux dabei zu helfen, es zu bekommen, erstellen wir ein CR GitRepository im Kubernetes-Cluster. Der Quellcontroller sieht es, geht zu Git und lädt es herunter.
Um dieses YAML in einem Cluster bereitzustellen, beschreiben wir eine Anpassungsressource.
Der Kustomize-Controller sieht es, geht zum Quellcontroller, ruft die YAML ab und stellt sie im Cluster bereit.
Der Helm-Controller erkennt, dass ein CR HelmRelease im Cluster erschienen ist, und geht zum Quell-Controller, um das beschriebene HELM-Diagramm abzurufen.
Damit der Quellcontroller dem HELM-Controller das angeforderte Diagramm übermitteln kann, müssen wir ein HelmRepository im CR-Cluster erstellen.
Der Helm-Controller ruft ein Diagramm vom Quell-Controller ab, erstellt ein Release und stellt es im Cluster bereit. Anschließend erstellt Kubernetes die erforderlichen Pods, geht zur Docker-Registrierung und lädt die entsprechenden Bilder herunter.
Um eine neue Version unserer Anwendung bereitzustellen, müssen wir dementsprechend ein neues Image, eine neue HelmRelease-Datei und möglicherweise ein neues HELM-Diagramm erstellen. Dann müssen wir sie in die entsprechenden Repositorys legen und warten, bis die Flux-Controller die oben beschriebene Arbeit in der Kette wiederholen.
Und um unsere Arbeit zu beenden, haben wir irgendwo einen Benachrichtigungscontroller installiert, der uns darüber informiert, was möglicherweise schief gelaufen ist.
Lassen Sie uns nun die benutzerdefinierten Ressourcen besprechen, mit denen Flux arbeitet.
Das erste ist das Git-Repository. Hier können wir die Adresse des Git-Repositorys (Zeile 14) und den Zweig angeben, den es betrachtet (Zeile 10).
Daher laden wir nur einen einzelnen Zweig herunter, nicht das gesamte Repository. Aber! Da wir verantwortungsbewusste Ingenieure sind und versuchen, das Zero-Trust-Konzept einzuhalten, sperren wir den Zugriff auf das Repository, erstellen ein Geheimnis mit einem Schlüssel im Kubernetes-Cluster und geben es an Flux weiter, damit es dorthin gelangen kann (Zeile 12).
Als nächstes folgt die Anpassung. Hier möchte ich Sie darauf aufmerksam machen, dass der Kustomize-Controller von Flux und Kustomize von den Autoren von Kubernetes zwei verschiedene Dinge sind. Ich weiß nicht, warum diese verwirrende Namensgebung gewählt wurde, aber es ist wichtig, sie nicht zu verwechseln.
Kustomization ist eine Möglichkeit, YAML (beliebig) aus einem Git-Repository in einem Cluster bereitzustellen. Hier müssen wir die Quelle angeben, aus der wir sie ablegen (Zeile 12 – der Name des oben beschriebenen CR GitRepository), das Verzeichnis, aus dem wir die YAMLs beziehen (Zeile 8), und wir können den Ziel-Namespace angeben, in dem sie abgelegt werden sollen (Zeile 13).
Als nächstes folgt die Helm-Veröffentlichung.
Hier können wir den Namen und die Diagrammversion angeben (Zeilen 10,11). Hier geben Sie Variablenwerte an, damit Helm die Veröffentlichung von Umgebung zu Umgebung anpassen kann (Zeilen 15–19). Dies ist eine äußerst wichtige und notwendige Funktion, da sich Ihre Umgebungen erheblich unterscheiden können. Sie geben auch die Quelle an, aus der das Helm-Diagramm entnommen werden soll (Zeilen 12, 13, 14). In diesem Fall handelt es sich um das Helm-Repository.
Aber! Da wir immer noch verantwortliche Ingenieure sind, haben wir auch engen Zugriff auf das Helm-Repository und geben Flux ein Geheimnis, um dorthin zu gelangen (Zeilen 7, 8).
Lassen Sie uns also eine kleine Checkliste erstellen, um festzuhalten, was wir gerade besprochen haben. Um mit GitOps zu beginnen, müssen wir plötzlich eine Reihe von Skripten schreiben (wir erinnern uns, dass es bei der unveränderlichen Infrastruktur um vollautomatische Lieferpipelines geht). Also müssen wir zunächst Folgendes erstellen:
Großartig, jetzt haben Sie eine Checkliste für GitOps. Weitergehen.
Mal sehen, was wir mit unserer Helm-Version im Allgemeinen bekommen. Es ist ziemlich offensichtlich, dass Git in diesem speziellen Fall nicht die einzige Quelle der Wahrheit sein kann. Wir haben mindestens zwei Ressourcen und zwei Artefakte außerhalb von Git, von denen diese Helm-Version abhängt:
Und wir können die Sache noch komplizierter machen und den Bereich der Helm-Chart-Versionen spezifizieren.
In diesem Fall überwacht und erstellt Flux neue Helm-Diagramme, die in diesem Bereich angezeigt werden. Darüber hinaus kann der Quellcontroller, über den wir verfügen, YAML als Quelle verwenden, einschließlich S3-Bundles.
Von dort aus können wir sowohl YAML- als auch Helm-Diagramme verwalten.
Darüber hinaus verfügen wir über Image-Automation-Controller, die neue Images in der Docker-Registrierung im Auge behalten und das Infrastruktur-Repository bearbeiten können.
Aber wir wollen keine HELM Chart Repo-Ops oder Docker Registry-Ops. Wir wollen so GitOps wie möglich sein. Also schauen wir uns die Dokumentation an und korrigieren die Prozesse zur Bereitstellung unseres Helm-Charts aus dem GIT-Repository (wir wählen das Anwendungs-Repository aus, um es zu speichern).
Dies zwingt uns, ein weiteres CR-GitRepository für das Anwendungs-Repository zu erstellen, ein Konto für den Zugriff von Flux darauf zu erstellen und ein Geheimnis mit Schlüsseln zu erstellen.
Gleichzeitig lösen wir in keiner Weise das Problem einer komplizierten Abhängigkeit vom Docker-Image.
Ich denke, das reicht für heute. Im 2. Teil erzähle ich euch, welche Probleme diese Güte hat. Ich werde diskutieren:
Ich hoffe, dieser Artikel war nützlich für Sie!