Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Hallo zusammen! Mein Name ist Pavel Agaletsky. Ich arbeite als Teamleiter in einem Team, das das Lamoda-Liefersystem entwickelt. 2018 habe ich auf der HighLoad++-Konferenz gesprochen und heute möchte ich eine Abschrift meines Berichts präsentieren.

Mein Thema ist den Erfahrungen unseres Unternehmens bei der Bereitstellung von Systemen und Diensten in verschiedenen Umgebungen gewidmet. Angefangen bei unseren prähistorischen Zeiten, als wir alle Systeme auf gewöhnlichen virtuellen Servern bereitgestellt haben, bis hin zum schrittweisen Übergang von Nomad zur Bereitstellung in Kubernetes. Ich erzähle Ihnen, warum wir das gemacht haben und welche Probleme wir dabei hatten.

Bereitstellen von Anwendungen auf VM

Beginnen wir mit der Tatsache, dass vor drei Jahren alle Systeme und Dienste des Unternehmens auf regulären virtuellen Servern bereitgestellt wurden. Technisch war es so organisiert, dass der gesamte Code für unsere Systeme gespeichert und mithilfe automatischer Assemblertools unter Verwendung von Jenkins zusammengestellt wurde. Mithilfe von Ansible wurde es von unserem Versionskontrollsystem auf virtuelle Server ausgerollt. Darüber hinaus wurde jedes System, über das unser Unternehmen verfügte, auf mindestens zwei Servern bereitgestellt: einer davon am Kopf und der zweite am Heck. Diese beiden Systeme waren in allen Einstellungen, Leistung, Konfiguration usw. absolut identisch. Der einzige Unterschied zwischen ihnen bestand darin, dass Head Benutzerverkehr empfing, während Tail nie Benutzerverkehr erhielt.

Warum wurde das gemacht?

Bei der Bereitstellung neuer Releases unserer Anwendung wollten wir einen reibungslosen Rollout, also ohne spürbare Konsequenzen für die Nutzer, gewährleisten. Dies wurde dadurch erreicht, dass die nächste mit Ansible kompilierte Version bis zum Ende ausgerollt wurde. Dort konnten die an der Bereitstellung beteiligten Personen überprüfen und sicherstellen, dass alles in Ordnung war: Alle Metriken, Abschnitte und Anwendungen funktionierten; die notwendigen Skripte werden gestartet. Erst nachdem sie überzeugt waren, dass alles in Ordnung sei, wurde der Verkehr umgestellt. Es begann, zu dem Server zu gelangen, der zuvor inaktiv war. Und derjenige, der zuvor der Kopf war, blieb ohne Benutzerverkehr, während sich immer noch die vorherige Version unserer Anwendung darauf befand.

Es verlief also reibungslos für die Benutzer. Weil die Umschaltung augenblicklich erfolgt, da lediglich der Balancer umgeschaltet wird. Sie können ganz einfach auf die vorherige Version zurückgreifen, indem Sie einfach den Balancer zurücksetzen. Wir konnten auch überprüfen, ob die Anwendung produktionsfähig war, noch bevor sie Benutzerverkehr erhielt, was sehr praktisch war.

Welche Vorteile sahen wir darin?

  1. Erstens reicht es es funktioniert einfach. Jeder versteht, wie ein solches Bereitstellungsschema funktioniert, da die meisten Menschen schon einmal auf regulären virtuellen Servern bereitgestellt haben.
  2. Das ist genug zuverlässig, da die Bereitstellungstechnologie einfach ist und von Tausenden von Unternehmen getestet wurde. Auf diese Weise werden Millionen von Servern bereitgestellt. Es ist schwer, etwas kaputt zu machen.
  3. Und endlich konnten wir es bekommen Atomare Einsätze. Bereitstellungen, die für Benutzer gleichzeitig erfolgen, ohne dass ein merklicher Wechsel zwischen der alten und der neuen Version stattfindet.

Aber wir sahen bei all dem auch einige Mängel:

  1. Neben der Produktionsumgebung und der Entwicklungsumgebung gibt es noch weitere Umgebungen. Zum Beispiel Qualitätssicherung und Vorproduktion. Zu dieser Zeit hatten wir viele Server und etwa 60 Dienste. Aus diesem Grund war es notwendig Pflegen Sie für jeden Dienst die neueste Version virtuelle Maschine. Wenn Sie außerdem Bibliotheken aktualisieren oder neue Abhängigkeiten installieren möchten, müssen Sie dies in allen Umgebungen tun. Sie mussten außerdem den Zeitpunkt, zu dem Sie die nächste neue Version Ihrer Anwendung bereitstellen werden, mit dem Zeitpunkt synchronisieren, zu dem Devops die erforderlichen Umgebungseinstellungen vornimmt. In diesem Fall kann es leicht passieren, dass sich unsere Umgebung in allen Umgebungen gleichzeitig etwas unterscheidet. Beispielsweise wird es in einer QA-Umgebung einige Versionen von Bibliotheken geben, in einer Produktionsumgebung jedoch unterschiedliche, was zu Problemen führen wird.
  2. Schwierigkeiten beim Aktualisieren von Abhängigkeiten Ihre Bewerbung. Es hängt nicht von Ihnen ab, sondern vom anderen Team. Nämlich vom Entwicklerteam, das die Server wartet. Sie müssen ihnen eine entsprechende Aufgabe und eine Beschreibung dessen geben, was Sie tun möchten.
  3. Damals wollten wir auch die großen Monolithen, die wir hatten, in einzelne kleine Dienste aufteilen, da wir wussten, dass es immer mehr davon geben würde. Zu diesem Zeitpunkt hatten wir bereits über 100 davon. Für jeden neuen Dienst musste eine eigene neue virtuelle Maschine erstellt werden, die auch gewartet und bereitgestellt werden musste. Außerdem braucht man nicht ein Auto, sondern mindestens zwei. Hinzu kommt die Qualitätssicherungsumgebung. Dies führt zu Problemen und erschwert Ihnen den Aufbau und Betrieb neuer Systeme. komplexer, teurer und langwieriger Prozess.

Daher haben wir beschlossen, dass es bequemer wäre, von der Bereitstellung normaler virtueller Maschinen zur Bereitstellung unserer Anwendungen in einem Docker-Container überzugehen. Wenn Sie über Docker verfügen, benötigen Sie ein System, das die Anwendung in einem Cluster ausführen kann, da Sie nicht einfach einen Container erstellen können. Normalerweise möchten Sie verfolgen, wie viele Container angehoben werden, damit diese automatisch angehoben werden. Aus diesem Grund mussten wir ein Steuerungssystem auswählen.

Wir haben lange darüber nachgedacht, welches wir nehmen könnten. Tatsache ist, dass dieser Bereitstellungsstapel auf regulären virtuellen Servern zu dieser Zeit etwas veraltet war, da diese nicht über die neuesten Betriebssystemversionen verfügten. Irgendwann gab es sogar FreeBSD, dessen Unterstützung nicht sehr praktisch war. Uns war klar, dass wir so schnell wie möglich auf Docker migrieren mussten. Unsere Entwickler haben ihre bisherigen Erfahrungen mit verschiedenen Lösungen geprüft und sich für ein System wie Nomad entschieden.

Wechseln Sie zu Nomad

Nomad ist ein Produkt von HashiCorp. Sie sind auch für ihre anderen Lösungen bekannt:

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

"Konsul" ist ein Tool zur Serviceerkennung.

„Terraform“ - ein System zur Verwaltung von Servern, mit dem Sie diese durch Konfiguration konfigurieren können, die sogenannte Infrastructure-as-a-Code.

"Landstreicher" ermöglicht Ihnen die Bereitstellung virtueller Maschinen lokal oder in der Cloud über bestimmte Konfigurationsdateien.

Nomad schien damals eine recht einfache Lösung zu sein, auf die man schnell umsteigen konnte, ohne die gesamte Infrastruktur zu ändern. Darüber hinaus ist es recht einfach zu erlernen. Deshalb haben wir es als Filtersystem für unseren Container gewählt.

Was benötigen Sie, um Ihr System auf Nomad bereitzustellen?

  1. Zuallererst brauchen Sie Docker-Bild Ihre Bewerbung. Sie müssen es erstellen und im Docker-Image-Repository platzieren. In unserem Fall handelt es sich um ein Artefakt – ein System, mit dem Sie verschiedene Artefakte unterschiedlicher Art hineinschieben können. Es kann Archive, Docker-Images, Composer-PHP-Pakete, NPM-Pakete usw. speichern.
  2. Auch benötigt Konfigurationsdatei, die Nomad mitteilt, was, wo und in welcher Menge Sie bereitstellen möchten.

Wenn wir über Nomad sprechen, verwendet es die HCL-Sprache als Informationsdateiformat, was für steht HashiCorp-Konfigurationssprache. Dies ist eine Obermenge von Yaml, mit der Sie Ihren Service in Nomad-Begriffen beschreiben können.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Sie können festlegen, wie viele Container Sie bereitstellen möchten und von welchen Bildern aus Sie während der Bereitstellung verschiedene Parameter an sie übergeben möchten. Daher geben Sie diese Datei an Nomad weiter und es startet entsprechend Container in die Produktion.

In unserem Fall haben wir festgestellt, dass es nicht sehr praktisch wäre, einfach absolut identische HCL-Dateien für jeden Dienst zu schreiben, da es viele Dienste gibt und man sie manchmal aktualisieren möchte. Es kommt vor, dass ein Dienst nicht in einer Instanz, sondern in verschiedenen Instanzen bereitgestellt wird. Beispielsweise verfügt eines der Systeme, die wir in Produktion haben, über mehr als 100 Instanzen in der Produktion. Sie laufen auf denselben Images, unterscheiden sich jedoch in den Konfigurationseinstellungen und Konfigurationsdateien.

Daher haben wir beschlossen, dass es für uns praktisch wäre, alle unsere Konfigurationsdateien für die Bereitstellung in einem gemeinsamen Repository zu speichern. Auf diese Weise waren sie sichtbar: Sie waren leicht zu warten und wir konnten sehen, welche Systeme wir hatten. Bei Bedarf ist es auch einfach, etwas zu aktualisieren oder zu ändern. Auch das Hinzufügen eines neuen Systems ist nicht schwierig – Sie müssen lediglich eine Konfigurationsdatei im neuen Verzeichnis erstellen. Darin befinden sich die folgenden Dateien: service.hcl, die eine Beschreibung unseres Dienstes enthält, und einige Env-Dateien, die die Konfiguration dieses Dienstes ermöglichen, der in der Produktion bereitgestellt wird.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Einige unserer Systeme werden jedoch nicht in einer Kopie, sondern in mehreren Exemplaren gleichzeitig in der Produktion eingesetzt. Daher haben wir beschlossen, dass es für uns praktischer wäre, die Konfigurationen nicht in ihrer reinen Form, sondern in ihrer Vorlagenform zu speichern. Und wir haben uns entschieden Jinja 2. In diesem Format speichern wir sowohl die Konfigurationen des Dienstes selbst als auch die dafür benötigten Env-Dateien.

Darüber hinaus haben wir im Repository ein für alle Projekte gemeinsames Bereitstellungsskript abgelegt, mit dem Sie Ihren Dienst starten und in der Produktion, in der gewünschten Umgebung und am gewünschten Ziel bereitstellen können. Als wir unsere HCL-Konfiguration in eine Vorlage umwandelten, sah die HCL-Datei, die zuvor eine reguläre Nomad-Konfiguration war, in diesem Fall etwas anders aus.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Das heißt, wir haben einige Konfigurationsspeicherortvariablen durch Variableneinfügungen ersetzt, die aus Env-Dateien oder anderen Quellen stammen. Darüber hinaus haben wir die Möglichkeit, HCL-Dateien dynamisch zu sammeln, das heißt, wir können nicht nur gewöhnliche Variableneinfügungen verwenden. Da Jinja Schleifen und Bedingungen unterstützt, können Sie dort auch Konfigurationsdateien erstellen, die sich je nachdem, wo genau Sie Ihre Anwendungen bereitstellen, ändern.

Beispielsweise möchten Sie Ihren Service für die Vorproduktion und Produktion bereitstellen. Nehmen wir an, Sie möchten in der Vorproduktion keine Cron-Skripte ausführen, sondern den Dienst lediglich in einer separaten Domäne sehen, um sicherzustellen, dass er funktioniert. Für jeden, der den Dienst bereitstellt, sieht der Prozess sehr einfach und transparent aus. Sie müssen lediglich die Datei „deploy.sh“ ausführen und angeben, welchen Dienst Sie auf welchem ​​Ziel bereitstellen möchten. Sie möchten beispielsweise ein bestimmtes System in Russland, Weißrussland oder Kasachstan einsetzen. Ändern Sie dazu einfach einen der Parameter und Sie erhalten die richtige Konfigurationsdatei.

Wenn der Nomad-Dienst bereits in Ihrem Cluster bereitgestellt ist, sieht es so aus.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Zunächst benötigen Sie eine Art Balancer draußen, der den gesamten Benutzerverkehr empfängt. Es wird mit Consul zusammenarbeiten und daraus herausfinden, wo, auf welchem ​​Knoten, unter welcher IP-Adresse sich ein bestimmter Dienst befindet, der einem bestimmten Domänennamen entspricht. Die Dienstleistungen in Consul werden von Nomad selbst bereitgestellt. Da es sich um Produkte desselben Unternehmens handelt, sind sie durchaus miteinander verwandt. Wir können sagen, dass Nomad sofort alle darin gestarteten Dienste in Consul registrieren kann.

Sobald Ihr Front-End-Load-Balancer weiß, an welchen Dienst er Datenverkehr senden soll, leitet er ihn an den entsprechenden Container oder mehrere Container weiter, die Ihrer Anwendung entsprechen. Natürlich muss auch an die Sicherheit gedacht werden. Auch wenn alle Dienste auf den gleichen virtuellen Maschinen in Containern laufen, erfordert dies in der Regel die Unterbindung des freien Zugriffs von jedem Dienst auf jeden anderen. Dies haben wir durch Segmentierung erreicht. Jeder Dienst wurde in einem eigenen virtuellen Netzwerk gestartet, in dem Routing-Regeln und Regeln zum Gewähren/Verweigern des Zugriffs auf andere Systeme und Dienste vorgeschrieben waren. Sie könnten sich sowohl innerhalb als auch außerhalb dieses Clusters befinden. Wenn Sie beispielsweise verhindern möchten, dass ein Dienst eine Verbindung zu einer bestimmten Datenbank herstellt, können Sie dies durch Segmentierung auf Netzwerkebene erreichen. Das heißt, Sie können nicht einmal versehentlich eine Verbindung von der Testumgebung zu Ihrer Produktionsdatenbank herstellen.

Wie viel hat uns der Übergang personell gekostet?

Die Umstellung des gesamten Unternehmens auf Nomad dauerte etwa 5-6 Monate. Wir haben uns von Dienst zu Dienst weiterentwickelt, aber in einem ziemlich schnellen Tempo. Jedes Team musste seine eigenen Container für die Dienste erstellen.

Wir haben den Ansatz gewählt, dass jedes Team unabhängig für die Docker-Images seiner Systeme verantwortlich ist. DevOps stellt die allgemeine Infrastruktur bereit, die für die Bereitstellung erforderlich ist, d. h. Unterstützung für den Cluster selbst, Unterstützung für das CI-System usw. Und zu diesem Zeitpunkt hatten wir mehr als 60 Systeme nach Nomad verlagert, was etwa 2 Containern entsprach.

Devops ist für die allgemeine Infrastruktur rund um Bereitstellung und Server verantwortlich. Und jedes Entwicklungsteam wiederum ist für die Implementierung von Containern für sein spezifisches System verantwortlich, da es das Team ist, das weiß, was es im Allgemeinen in einem bestimmten Container benötigt.

Gründe für den Verzicht auf Nomad

Welche Vorteile hatten wir durch die Umstellung auf die Bereitstellung unter anderem mit Nomad und Docker?

  1. Wir gleiche Bedingungen vorausgesetzt für alle Umgebungen. In der Entwicklung, der Qualitätssicherungsumgebung, der Vorproduktion und der Produktion werden dieselben Containerbilder mit denselben Abhängigkeiten verwendet. Dementsprechend haben Sie praktisch keine Chance, dass das, was am Ende in die Produktion gelangt, nicht das ist, was Sie zuvor lokal oder in Ihrer Testumgebung getestet haben.
  2. Wir fanden auch, dass es reicht Einfaches Hinzufügen eines neuen Dienstes. Aus der Sicht der Bereitstellung ist die Einführung neuer Systeme sehr einfach. Gehen Sie einfach in das Repository, in dem die Konfigurationen gespeichert sind, fügen Sie dort eine weitere Konfiguration für Ihr System hinzu, und schon sind Sie fertig. Sie können Ihr System ohne zusätzlichen Aufwand seitens der Entwickler für die Produktion bereitstellen.
  3. alle Konfigurationsdateien in einem gemeinsamen Repository Es stellte sich heraus, dass es überprüft wurde. Als wir unsere Systeme mithilfe virtueller Server bereitgestellt haben, verwendeten wir Ansible, bei dem sich die Konfigurationen im selben Repository befanden. Für die meisten Entwickler war dies jedoch etwas schwieriger zu handhaben. Hier ist die Menge an Konfigurationen und Code, die Sie hinzufügen müssen, um den Dienst bereitzustellen, viel kleiner geworden. Außerdem ist es für Entwickler sehr einfach, das Problem zu beheben oder zu ändern. Bei Umstellungen, beispielsweise auf eine neue Version von Nomad, können sie alle am selben Ort befindlichen Betriebsdateien übernehmen und in großen Mengen aktualisieren.

Aber wir sind auch auf mehrere Nachteile gestoßen:

Es stellte sich heraus, dass wir konnte keine nahtlosen Bereitstellungen erreichen im Fall von Nomad. Beim Ausrollen von Containern unter unterschiedlichen Bedingungen könnte sich herausstellen, dass er läuft, und Nomad nimmt ihn als einen Container wahr, der bereit ist, Datenverkehr zu empfangen. Dies geschah, bevor die darin enthaltene Anwendung überhaupt gestartet werden konnte. Aus diesem Grund begann das System für kurze Zeit 500 Fehler zu erzeugen, weil der Datenverkehr begann, zu einem Container zu fließen, der noch nicht bereit war, ihn anzunehmen.

Wir sind auf einige gestoßen durch die Moore. Der größte Fehler besteht darin, dass Nomad mit einem großen Cluster nicht gut zurechtkommt, wenn Sie über viele Systeme und Container verfügen. Wenn Sie einen der im Nomad-Cluster enthaltenen Server zur Wartung ausbauen möchten, ist die Wahrscheinlichkeit ziemlich hoch, dass sich der Cluster nicht gut anfühlt und auseinanderfällt. Einige Container können beispielsweise fallen und nicht steigen – das wird Sie später sehr viel kosten, wenn sich alle Ihre Produktionssysteme in einem von Nomad verwalteten Cluster befinden.

Also beschlossen wir, darüber nachzudenken, wohin wir als nächstes gehen sollten. Zu diesem Zeitpunkt wurde uns viel bewusster, was wir erreichen wollten. Nämlich: Wir wollen Zuverlässigkeit, etwas mehr Funktionen als Nomad bietet und ein ausgereifteres, stabileres System.

In diesem Zusammenhang fiel unsere Wahl auf Kubernetes als beliebteste Plattform zum Starten von Clustern. Vor allem angesichts der Tatsache, dass die Größe und Anzahl unserer Container groß genug war. Für solche Zwecke schien Kubernetes das am besten geeignete System zu sein, das wir in Betracht ziehen konnten.

Übergang zu Kubernetes

Ich erzähle Ihnen ein wenig über die Grundkonzepte von Kubernetes und wie sie sich von Nomad unterscheiden.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Das grundlegendste Konzept in Kubernetes ist zunächst das Pod-Konzept. Schote ist eine Gruppe von einem oder mehreren Containern, die immer zusammen laufen. Und sie arbeiten immer so, als ob sie ausschließlich auf einer virtuellen Maschine wären. Sie sind untereinander über IP 127.0.0.1 auf verschiedenen Ports erreichbar.

Nehmen wir an, Sie haben eine PHP-Anwendung, die aus Nginx und PHP-FPM besteht – dem klassischen Schema. Höchstwahrscheinlich möchten Sie sowohl die Nginx- als auch die PHP-FPM-Container jederzeit zusammenhalten. Mit Kubernetes können Sie dies erreichen, indem Sie sie als einen gemeinsamen Pod beschreiben. Genau das konnten wir mit Nomad nicht erreichen.

Das zweite Konzept ist Einsatz. Tatsache ist, dass die Schote selbst ein vergängliches Ding ist; sie beginnt und verschwindet. Möchten Sie zuerst alle Ihre vorherigen Container löschen und dann neue Versionen auf einmal starten, oder möchten Sie sie schrittweise ausrollen? Dies ist der Prozess, für den das Konzept der Bereitstellung verantwortlich ist. Es beschreibt, wie Sie Ihre Pods bereitstellen, in welcher Menge und wie Sie sie aktualisieren.

Das dritte Konzept ist . Ihr Dienst ist eigentlich Ihr System, das einen Teil des Datenverkehrs empfängt und ihn dann an einen oder mehrere Pods weiterleitet, die Ihrem Dienst entsprechen. Das heißt, man kann damit sagen, dass der gesamte eingehende Datenverkehr zu diesem oder jenem Dienst mit diesem und jenem Namen an diese spezifischen Pods gesendet werden muss. Gleichzeitig sorgt es für einen Traffic-Balancing. Das heißt, Sie können zwei Pods Ihrer Anwendung starten und der gesamte eingehende Datenverkehr wird gleichmäßig auf die mit diesem Dienst verbundenen Pods verteilt.

Und das vierte Grundkonzept ist Eintritt. Dies ist ein Dienst, der auf einem Kubernetes-Cluster ausgeführt wird. Es fungiert als externer Load Balancer, der alle Anfragen übernimmt. Mithilfe der Kubernetes-API kann Ingress bestimmen, wohin diese Anfragen gesendet werden sollen. Darüber hinaus macht er dies sehr flexibel. Man kann sagen, dass alle Anfragen an diesen Host und diese oder jene URL an diesen Dienst gesendet werden. Und diese Anfragen, die an diesen Host und an eine andere URL gehen, werden an einen anderen Dienst gesendet.

Das Coolste aus der Sicht eines Entwicklers einer Anwendung ist, dass man alles selbst verwalten kann. Durch Festlegen der Ingress-Konfiguration können Sie den gesamten Datenverkehr, der zu dieser oder jener API kommt, an separate Container senden, die beispielsweise in Go geschrieben sind. Aber dieser Datenverkehr, der zur gleichen Domäne, aber zu einer anderen URL gelangt, sollte an in PHP geschriebene Container gesendet werden, in denen es zwar viel Logik gibt, die aber nicht sehr schnell sind.

Wenn wir alle diese Konzepte mit Nomad vergleichen, können wir sagen, dass die ersten drei Konzepte alle zusammen Service sind. Und das letzte Konzept fehlt in Nomad selbst. Wir haben einen externen Balancer verwendet: Es könnte Haproxy, Nginx, Nginx+ usw. sein. Im Falle eines Cubes müssen Sie dieses zusätzliche Konzept nicht separat einführen. Wenn man Ingress jedoch intern betrachtet, ist es entweder Nginx, Haproxy oder Traefik, aber irgendwie in Kubernetes integriert.

Bei allen von mir beschriebenen Konzepten handelt es sich tatsächlich um Ressourcen, die innerhalb eines Kubernetes-Clusters vorhanden sind. Um sie im Cube zu beschreiben, wird ein Yaml-Format verwendet, das im Fall von Nomad besser lesbar und vertrauter ist als HCL-Dateien. Aber strukturell beschreiben sie beispielsweise im Fall von Pod dasselbe. Sie sagen: „Ich möchte dort diese und jene Kapseln einsetzen, mit diesen und jenen Bildern, in diesen und jenen Mengen.“

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Darüber hinaus wurde uns klar, dass wir nicht jede einzelne Ressource von Hand erstellen wollten: Bereitstellung, Dienste, Ingress usw. Stattdessen wollten wir jedes unserer Systeme während der Bereitstellung in Bezug auf Kubernetes beschreiben, damit wir nicht alle erforderlichen Ressourcenabhängigkeiten manuell in der richtigen Reihenfolge neu erstellen müssen. Helm wurde als System ausgewählt, das uns dies ermöglichte.

Grundlegende Konzepte in Helm

Helm ist Paket-Manager für Kubernetes. Es ist der Funktionsweise von Paketmanagern in Programmiersprachen sehr ähnlich. Sie ermöglichen es Ihnen, einen Dienst, der beispielsweise aus Deployment Nginx, Deployment PHP-FPM, Konfiguration für Ingress und Configmaps (dies ist eine Entität, mit der Sie Env und andere Parameter für Ihr System festlegen können) besteht, in Form von so- zu speichern. sogenannte Diagramme. Gleichzeitig Helm läuft auf Kubernetes. Das heißt, es handelt sich hierbei nicht um ein abseits stehendes System, sondern lediglich um einen weiteren Dienst, der im Cube gestartet wird. Sie interagieren mit ihm über seine API über einen Konsolenbefehl. Der Komfort und das Schöne daran ist, dass Ihre Dienste nicht verloren gehen, selbst wenn das Ruder kaputt geht oder Sie es aus dem Cluster entfernen, da das Ruder im Wesentlichen nur zum Starten des Systems dient. Kubernetes ist dann selbst für die Leistung und den Zustand der Dienste verantwortlich.

Das haben wir auch gemerkt Templateisierung, wozu wir zuvor gezwungen waren, indem wir Jinja in unsere Konfigurationen einführten, ist eines der Hauptfeatures von Helm. Alle Konfigurationen, die Sie für Ihre Systeme erstellen, werden in Helm in Form von Vorlagen gespeichert, ein wenig ähnlich wie Jinja, verwenden aber tatsächlich die Vorlagen der Go-Sprache, in der Helm geschrieben ist, wie Kubernetes.

Helm fügt uns noch ein paar weitere Konzepte hinzu.

Chart - Dies ist eine Beschreibung Ihrer Dienstleistung. In anderen Paketmanagern würde man es als Paket, Bundle oder ähnlich bezeichnen. Hier heißt es Diagramm.

Werte sind die Variablen, die Sie zum Erstellen Ihrer Konfigurationen aus Vorlagen verwenden möchten.

Loslassen. Jedes Mal, wenn ein Dienst, der mit Helm bereitgestellt wird, eine inkrementelle Version der Version erhält. Helm merkt sich die Dienstkonfiguration in der vorherigen Version, der Version davor usw. Wenn Sie daher ein Rollback durchführen müssen, führen Sie einfach den Helm-Callback-Befehl aus und verweisen Sie ihn auf die vorherige Release-Version. Selbst wenn die entsprechende Konfiguration in Ihrem Repository zum Zeitpunkt des Rollbacks nicht verfügbar ist, merkt sich Helm dennoch den Status und setzt Ihr System auf den Zustand zurück, in dem es sich in der vorherigen Version befand.

Wenn wir Helm verwenden, werden reguläre Konfigurationen für Kubernetes auch in Vorlagen umgewandelt, in denen es möglich ist, Variablen und Funktionen zu verwenden und bedingte Anweisungen anzuwenden. Auf diese Weise können Sie Ihre Dienstkonfiguration abhängig von der Umgebung erfassen.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

In der Praxis haben wir beschlossen, die Dinge etwas anders zu machen als bei Nomad. Wenn in Nomad sowohl Bereitstellungskonfigurationen als auch N-Variablen, die für die Bereitstellung unseres Dienstes benötigt wurden, in einem Repository gespeichert waren, haben wir uns hier entschieden, sie in zwei separate Repositorys aufzuteilen. Das „Deploy“-Repository speichert nur n-Variablen, die für die Bereitstellung benötigt werden, und das „Helm“-Repository speichert Konfigurationen oder Diagramme.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Was hat uns das gebracht?

Und das, obwohl wir in den Konfigurationsdateien selbst keine wirklich sensiblen Daten speichern. Zum Beispiel Passwörter für Datenbanken. Sie werden als Geheimnisse in Kubernetes gespeichert, dennoch gibt es dort immer noch bestimmte Dinge, auf die wir nicht jedem Zugriff geben wollen. Daher ist der Zugriff auf das „Deploy“-Repository eingeschränkter und das „Helm“-Repository enthält lediglich eine Beschreibung des Dienstes. Aus diesem Grund ist es für einen größeren Personenkreis sicher zugänglich.

Da wir nicht nur über Produktionsumgebungen, sondern auch über andere Umgebungen verfügen, können wir dank dieser Trennung unsere Helmdiagramme wiederverwenden, um Dienste nicht nur in der Produktion, sondern beispielsweise auch in einer QS-Umgebung bereitzustellen. Sogar um sie lokal bereitzustellen Minikube – Dies ist eine Sache für die lokale Ausführung von Kubernetes.

In jedem Repository haben wir für jeden Dienst eine Unterteilung in separate Verzeichnisse hinterlassen. Das heißt, in jedem Verzeichnis gibt es Vorlagen, die sich auf das entsprechende Diagramm beziehen und die Ressourcen beschreiben, die zum Betrieb unseres Systems bereitgestellt werden müssen. Wir haben nur envs im „deploy“-Repository belassen. In diesem Fall haben wir keine Vorlagen mit Jinja verwendet, da Helm selbst standardmäßig Vorlagen bereitstellt – dies ist eine seiner Hauptfunktionen.

Wir haben ein Bereitstellungsskript hinterlassen – „deploy.sh“, das den Start für die Bereitstellung mithilfe von Helm vereinfacht und standardisiert. Für alle, die eine Bereitstellung durchführen möchten, sieht die Bereitstellungsoberfläche also genauso aus wie bei der Bereitstellung über Nomad. Dieselbe „deploy.sh“, der Name Ihres Dienstes und der Ort, an dem Sie ihn bereitstellen möchten. Dies führt dazu, dass der Helm intern startet. Es sammelt wiederum Konfigurationen aus Vorlagen, fügt die erforderlichen Wertedateien in sie ein, stellt sie dann bereit und startet sie in Kubernetes.

Befund

Der Kubernetes-Dienst scheint komplexer zu sein als Nomad.

Bereitstellung von Anwendungen auf VM, Nomad und Kubernetes

Hier gelangt der ausgehende Datenverkehr zum Ingress. Dabei handelt es sich lediglich um den Front-Controller, der alle Anfragen entgegennimmt und diese anschließend entsprechend den Anfragedaten an die Dienste weiterleitet. Es bestimmt sie anhand von Konfigurationen, die Teil der Beschreibung Ihrer Anwendung im Helm sind und die Entwickler selbst festlegen. Der Dienst sendet Anfragen an seine Pods, also bestimmte Container, und verteilt den eingehenden Datenverkehr auf alle Container, die zu diesem Dienst gehören. Und natürlich sollten wir nicht vergessen, dass wir von der Sicherheit auf Netzwerkebene nicht abweichen dürfen. Daher funktioniert die Segmentierung in einem Kubernetes-Cluster, der auf Tagging basiert. Alle Dienste verfügen über bestimmte Tags, mit denen die Zugriffsrechte der Dienste auf bestimmte externe/interne Ressourcen innerhalb oder außerhalb des Clusters verknüpft sind.

Als wir den Übergang vollzogen, stellten wir fest, dass Kubernetes über alle Funktionen von Nomad verfügte, die wir zuvor genutzt hatten, und außerdem viele neue Dinge hinzufügte. Es kann durch Plugins und sogar durch benutzerdefinierte Ressourcentypen erweitert werden. Das heißt, Sie haben die Möglichkeit, nicht nur etwas zu verwenden, das standardmäßig mit Kubernetes geliefert wird, sondern auch Ihre eigene Ressource und Ihren eigenen Dienst zu erstellen, der Ihre Ressource liest. Dadurch erhalten Sie zusätzliche Möglichkeiten, Ihr System zu erweitern, ohne Kubernetes neu installieren zu müssen und ohne dass Modifikationen erforderlich sind.

Ein Beispiel für eine solche Verwendung ist Prometheus, das in unserem Kubernetes-Cluster ausgeführt wird. Damit es mit der Erfassung von Metriken von einem bestimmten Dienst beginnen kann, müssen wir der Dienstbeschreibung einen zusätzlichen Ressourcentyp hinzufügen, den sogenannten Dienstmonitor. Da Prometheus beim Start in Kubernetes einen benutzerdefinierten Ressourcentyp lesen kann, beginnt es automatisch mit der Erfassung von Metriken aus dem neuen System. Es ist ziemlich praktisch.

Die erste Bereitstellung auf Kubernetes erfolgte im März 2018. Und in dieser Zeit hatten wir nie Probleme damit. Es funktioniert recht stabil und ohne nennenswerte Fehler. Darüber hinaus können wir es weiter ausbauen. Heute haben wir genug von den Möglichkeiten, die es bietet, und das Entwicklungstempo von Kubernetes gefällt uns sehr gut. Derzeit befinden sich mehr als 3000 Container in Kubernetes. Der Cluster belegt mehrere Knoten. Gleichzeitig ist es wartungsfreundlich, stabil und sehr gut kontrollierbar.

Source: habr.com

Kommentar hinzufügen