Produktionsreife Bilder für k8s

In dieser Geschichte geht es darum, wie wir Container in einer Produktionsumgebung verwenden, insbesondere Kubernetes. Der Artikel widmet sich dem Sammeln von Metriken und Protokollen aus Containern sowie dem Erstellen von Bildern.

Produktionsreife Bilder für k8s

Wir sind vom Fintech-Unternehmen Exness, das Dienstleistungen für den Online-Handel und Fintech-Produkte für B2B und B2C entwickelt. Unsere Forschung und Entwicklung besteht aus vielen verschiedenen Teams, die Entwicklungsabteilung hat mehr als 100 Mitarbeiter.

Wir repräsentieren das Team, das für die Plattform verantwortlich ist, auf der unsere Entwickler Code sammeln und ausführen können. Wir sind insbesondere für die Erfassung, Speicherung und Berichterstattung von Metriken, Protokollen und Ereignissen aus Anwendungen verantwortlich. Wir betreiben derzeit rund dreitausend Docker-Container in einer Produktionsumgebung, pflegen unseren 50-TB-Big-Data-Speicher und bieten Architekturlösungen an, die auf unserer Infrastruktur basieren: Kubernetes, Rancher und verschiedene öffentliche Cloud-Anbieter. 

Unsere Motivation

Was brennt? Niemand kann antworten. Wo ist der Herd? Es ist schwer zu verstehen. Wann fing es Feuer? Sie können es herausfinden, aber nicht sofort. 

Produktionsreife Bilder für k8s

Warum stehen einige Container, während andere umgefallen sind? Welcher Container war schuld? Schließlich sind die Behälter von außen gleich, aber im Inneren hat jeder seinen eigenen Neo.

Produktionsreife Bilder für k8s

Unsere Entwickler sind kompetente Leute. Sie erbringen gute Dienstleistungen, die dem Unternehmen Gewinn bringen. Es kommt jedoch zu Fehlern, wenn Container mit Anwendungen in die Irre gehen. Ein Container verbraucht zu viel CPU, ein anderer verbraucht das Netzwerk, ein dritter verbraucht E/A-Vorgänge und beim vierten ist völlig unklar, was er mit Sockets macht. Alles fällt und das Schiff sinkt. 

Agenten

Um zu verstehen, was im Inneren passiert, haben wir uns entschieden, Agenten direkt in Containern zu platzieren.

Produktionsreife Bilder für k8s

Bei diesen Agenten handelt es sich um Rückhalteprogramme, die Container in einem Zustand halten, in dem sie sich nicht gegenseitig zerstören. Agenten sind standardisiert, was einen standardisierten Ansatz für die Wartung von Containern ermöglicht. 

In unserem Fall müssen Agenten Protokolle in einem Standardformat bereitstellen, die mit Tags versehen und gedrosselt sind. Sie sollten uns auch standardisierte Metriken liefern, die aus der Perspektive einer Geschäftsanwendung erweiterbar sind.

Mit Agenten sind auch Dienstprogramme für Betrieb und Wartung gemeint, die in verschiedenen Orchestrierungssystemen arbeiten können, die unterschiedliche Images unterstützen (Debian, Alpine, Centos usw.).

Schließlich müssen Agenten einfaches CI/CD unterstützen, das Docker-Dateien enthält. Andernfalls bricht das Schiff auseinander, da Container auf „krummen“ Schienen angeliefert werden.

Erstellen Sie den Prozess und das Ziel-Image-Gerät

Um alles standardisiert und verwaltbar zu halten, muss eine Art Standard-Build-Prozess befolgt werden. Deshalb haben wir uns entschieden, Container für Container zu sammeln – das ist Rekursion.

Produktionsreife Bilder für k8s

Hier werden die Behälter durch durchgezogene Umrisse dargestellt. Gleichzeitig beschlossen sie, ihnen Verteilungspakete beizufügen, damit „das Leben nicht wie Himbeeren erscheint“. Warum dies geschehen ist, erläutern wir im Folgenden.
 
Das Ergebnis ist ein Build-Tool – ein versionspezifischer Container, der auf bestimmte Distributionsversionen und bestimmte Skriptversionen verweist.

Wie nutzen wir es? Wir haben einen Docker Hub, der einen Container enthält. Wir spiegeln es in unserem System, um externe Abhängigkeiten zu beseitigen. Das Ergebnis ist ein gelb markierter Container. Wir erstellen eine Vorlage, um alle benötigten Distributionen und Skripte im Container zu installieren. Anschließend stellen wir ein gebrauchsfertiges Image zusammen: Entwickler fügen darin Code und einige ihrer eigenen speziellen Abhängigkeiten ein. 

Was ist das Gute an diesem Ansatz? 

  • Erstens vollständige Versionskontrolle der Build-Tools – Build-Container-, Skript- und Distributionsversionen. 
  • Zweitens haben wir eine Standardisierung erreicht: Wir erstellen Vorlagen, Zwischen- und gebrauchsfertige Bilder auf die gleiche Weise. 
  • Drittens ermöglichen uns Container Mobilität. Heute verwenden wir Gitlab, morgen wechseln wir zu TeamCity oder Jenkins und können unsere Container auf die gleiche Weise betreiben. 
  • Viertens: Minimierung von Abhängigkeiten. Es war kein Zufall, dass wir Distributionskits in den Container gelegt haben, denn so können wir vermeiden, sie jedes Mal aus dem Internet herunterzuladen. 
  • Fünftens hat sich die Erstellungsgeschwindigkeit erhöht – durch das Vorhandensein lokaler Kopien von Bildern können Sie Zeitverschwendung beim Herunterladen vermeiden, da ein lokales Bild vorhanden ist. 

Mit anderen Worten: Wir haben einen kontrollierten und flexiblen Montageprozess erreicht. Wir verwenden dieselben Tools, um alle vollständig versionierten Container zu erstellen. 

Wie unser Build-Vorgang funktioniert

Produktionsreife Bilder für k8s

Die Assembly wird mit einem Befehl gestartet, der Prozess wird im Bild ausgeführt (rot hervorgehoben). Der Entwickler hat eine Docker-Datei (gelb hervorgehoben), wir rendern sie und ersetzen Variablen durch Werte. Und nebenbei fügen wir Kopf- und Fußzeilen hinzu – das sind unsere Agenten. 

Der Header fügt Verteilungen aus den entsprechenden Bildern hinzu. Und die Fußzeile installiert unsere Dienste im Inneren, konfiguriert den Start von Workload, Protokollierung und anderen Agenten, ersetzt den Einstiegspunkt usw. 

Produktionsreife Bilder für k8s

Wir haben lange darüber nachgedacht, ob wir einen Supervisor installieren sollten. Am Ende entschieden wir, dass wir ihn brauchten. Wir haben uns für S6 entschieden. Der Supervisor sorgt für die Containerverwaltung: Ermöglicht Ihnen die Verbindung zu ihm, wenn der Hauptprozess abstürzt, und ermöglicht die manuelle Verwaltung des Containers, ohne ihn neu zu erstellen. Protokolle und Metriken sind Prozesse, die im Container ausgeführt werden. Sie müssen auch irgendwie kontrolliert werden, und wir tun dies mit Hilfe eines Vorgesetzten. Schließlich kümmert sich der S6 um Housekeeping, Signalverarbeitung und andere Aufgaben.

Da wir unterschiedliche Orchestrierungssysteme verwenden, muss der Container nach dem Erstellen und Ausführen verstehen, in welcher Umgebung er sich befindet, und entsprechend der Situation handeln. Zum Beispiel:
Dies ermöglicht uns, ein Image zu erstellen und es in verschiedenen Orchestrierungssystemen auszuführen, und es wird unter Berücksichtigung der Besonderheiten dieses Orchestrierungssystems gestartet.

 Produktionsreife Bilder für k8s

Für denselben Container erhalten wir in Docker und Kubernetes unterschiedliche Prozessbäume:

Produktionsreife Bilder für k8s

Die Nutzlast wird unter der Aufsicht von S6 ausgeführt. Achten Sie auf Sammler und Ereignisse – das sind unsere Agenten, die für Protokolle und Metriken verantwortlich sind. Kubernetes verfügt nicht über sie, Docker jedoch schon. Warum? 

Wenn wir uns die Spezifikation des „Pods“ (im Folgenden: Kubernetes-Pod) ansehen, werden wir sehen, dass der Ereigniscontainer in einem Pod ausgeführt wird, der über einen separaten Collector-Container verfügt, der die Funktion des Sammelns von Metriken und Protokollen übernimmt. Wir können die Fähigkeiten von Kubernetes nutzen: Container in einem Pod, in einem einzelnen Prozess und/oder Netzwerkraum ausführen. Stellen Sie Ihre Agenten tatsächlich vor und führen Sie einige Funktionen aus. Und wenn derselbe Container in Docker gestartet wird, erhält er dieselben Ausgabefunktionen, d. h. er kann Protokolle und Metriken liefern, da die Agenten intern gestartet werden. 

Metriken und Protokolle

Die Bereitstellung von Metriken und Protokollen ist eine komplexe Aufgabe. Ihre Entscheidung hat mehrere Aspekte.
Die Infrastruktur wird für die Ausführung der Nutzlast erstellt und nicht für die Massenlieferung von Protokollen. Das heißt, dieser Prozess muss mit minimalen Anforderungen an die Containerressourcen durchgeführt werden. Wir sind bestrebt, unseren Entwicklern zu helfen: „Besorgen Sie sich einen Docker Hub-Container, führen Sie ihn aus und wir können die Protokolle liefern.“ 

Der zweite Aspekt ist die Begrenzung des Protokollvolumens. Tritt in mehreren Containern ein Anstieg des Protokollvolumens auf (die Anwendung gibt einen Stack-Trace in einer Schleife aus), erhöht sich die Belastung der CPU, der Kommunikationskanäle und des Protokollverarbeitungssystems, was sich auf den Betrieb des Hosts als Host auswirkt Ganze und andere Container auf dem Host, dann führt dies manchmal zum „Absturz“ des Hosts. 

Der dritte Aspekt besteht darin, dass so viele Metrikerfassungsmethoden wie möglich sofort unterstützt werden müssen. Vom Lesen von Dateien und Abfragen des Prometheus-Endpunkts bis hin zur Verwendung anwendungsspezifischer Protokolle.

Und der letzte Aspekt besteht darin, den Ressourcenverbrauch zu minimieren.

Wir haben uns für eine Open-Source-Go-Lösung namens Telegraf entschieden. Dies ist ein universeller Anschluss, der mehr als 140 Arten von Eingangskanälen (Eingangs-Plugins) und 30 Arten von Ausgangskanälen (Ausgangs-Plugins) unterstützt. Wir haben es fertiggestellt und erzählen Ihnen nun am Beispiel von Kubernetes, wie wir es verwenden. 

Produktionsreife Bilder für k8s

Nehmen wir an, ein Entwickler stellt eine Arbeitslast bereit und Kubernetes erhält eine Anfrage zum Erstellen eines Pods. Zu diesem Zeitpunkt wird für jeden Pod automatisch ein Container namens Collector erstellt (wir verwenden den Mutation-Webhook). Collector ist unser Agent. Zu Beginn konfiguriert sich dieser Container für die Zusammenarbeit mit Prometheus und dem Protokollerfassungssystem.

  • Dazu nutzt es Pod-Annotationen und erstellt je nach Inhalt beispielsweise einen Prometheus-Endpunkt; 
  • Basierend auf der Pod-Spezifikation und den spezifischen Containereinstellungen wird entschieden, wie Protokolle bereitgestellt werden.

Wir sammeln Protokolle über die Docker-API: Entwickler müssen sie nur in stdout oder stderr ablegen, und Collector kümmert sich darum. Protokolle werden in Blöcken mit einer gewissen Verzögerung erfasst, um eine mögliche Host-Überlastung zu verhindern. 

Metriken werden über Workload-Instanzen (Prozesse) hinweg in Containern gesammelt. Alles wird mit Tags versehen: Namespace, Under usw. und dann in das Prometheus-Format konvertiert – und steht zur Sammlung zur Verfügung (außer Protokolle). Wir senden auch Protokolle, Metriken und Ereignisse an Kafka und weiter:

  • Protokolle sind in Graylog verfügbar (zur visuellen Analyse);
  • Protokolle, Metriken und Ereignisse werden zur langfristigen Speicherung an Clickhouse gesendet.

In AWS funktioniert alles genauso, nur ersetzen wir Graylog durch Kafka durch Cloudwatch. Wir senden die Protokolle dorthin und alles ist sehr praktisch: Es ist sofort klar, zu welchem ​​Cluster und Container sie gehören. Dasselbe gilt auch für Google Stackdriver. Das heißt, unser Schema funktioniert sowohl vor Ort mit Kafka als auch in der Cloud. 

Wenn wir kein Kubernetes mit Pods haben, ist das Schema etwas komplizierter, funktioniert aber nach den gleichen Prinzipien.

Produktionsreife Bilder für k8s

Die gleichen Prozesse werden im Container ausgeführt, sie werden mit S6 orchestriert. Alle gleichen Prozesse werden im selben Container ausgeführt.

Infolgedessen

Wir haben eine Komplettlösung zum Erstellen und Starten von Bildern erstellt, mit Optionen zum Sammeln und Bereitstellen von Protokollen und Metriken:

  • Wir haben einen standardisierten Ansatz für die Zusammenstellung von Bildern entwickelt und darauf basierend CI-Vorlagen entwickelt;
  • Datenerfassungsagenten sind unsere Telegraf-Erweiterungen. Wir haben sie in der Produktion gut getestet;
  • Wir verwenden Mutation Webhook, um Container mit Agenten in Pods zu implementieren; 
  • Integriert in das Kubernetes/Rancher-Ökosystem;
  • Wir können dieselben Container in verschiedenen Orchestrierungssystemen ausführen und das erwartete Ergebnis erzielen;
  • Erstellt eine vollständig dynamische Containerverwaltungskonfiguration. 

Mitverfasser: Ilja Prudnikow

Source: habr.com

Kommentar hinzufügen