Heute möchte ich darüber sprechen, wie man Anwendungen schreibt und welche Voraussetzungen dafür gelten, dass Ihre Anwendung in Kubernetes gut funktioniert. Damit es bei der Anwendung keine Kopfschmerzen gibt, man keine „Kratzer“ drumherum erfinden und bauen muss – und alles so funktioniert, wie es Kubernetes selbst vorgesehen hat.
Dieser Vortrag ist Teil von „" Sie können sich die offenen theoretischen Vorlesungen der Abendschule ansehen . Für diejenigen, die Text statt Video bevorzugen, haben wir diesen Artikel vorbereitet.
Mein Name ist Pavel Selivanov, derzeit bin ich der führende DevOps-Ingenieur bei Mail.ru Cloud Solutions, wir erstellen Clouds, wir erstellen Management-Kubernetes und so weiter. Zu meinen Aufgaben gehört nun die Unterstützung bei der Entwicklung, die Einführung dieser Clouds, die Einführung der von uns geschriebenen Anwendungen und die direkte Entwicklung der Tools, die wir unseren Nutzern zur Verfügung stellen.

Ich mache DevOps, ich glaube, seit wahrscheinlich drei Jahren. Aber im Prinzip mache ich das, was DevOps macht, wahrscheinlich schon seit etwa fünf Jahren. Davor war ich hauptsächlich mit Verwaltungsaufgaben beschäftigt. Ich habe vor langer Zeit angefangen, mit Kubernetes zu arbeiten – wahrscheinlich sind seit dem Beginn meiner Arbeit damit etwa vier Jahre vergangen.
Im Allgemeinen habe ich angefangen, als Kubernetes wahrscheinlich Version 1.3 und vielleicht 1.2 hatte – als es noch in den Kinderschuhen steckte. Jetzt steckt es nicht mehr in den Kinderschuhen – und es ist offensichtlich, dass auf dem Markt eine große Nachfrage nach Ingenieuren besteht, die Kubernetes beherrschen möchten. Und die Unternehmen haben einen sehr hohen Bedarf an solchen Leuten. Daher ist dieser Vortrag tatsächlich erschienen.
Wenn wir nach dem Plan darüber sprechen, worüber ich sprechen werde, sieht es so aus, in Klammern steht (TL;DR) – „zu lang; nicht lesen“. Mein heutiger Vortrag wird aus endlosen Listen bestehen.

Tatsächlich mag ich selbst solche Präsentationen nicht, wenn sie gemacht werden, aber das ist ein so großes Thema, dass ich bei der Vorbereitung dieser Präsentation einfach nicht wirklich herausgefunden habe, wie ich diese Informationen anders organisieren könnte.
Denn im Großen und Ganzen lauten diese Informationen „Strg+C, Strg+V“, unter anderem aus unserem Wiki im DevOps-Bereich, wo wir Anforderungen an Entwickler geschrieben haben: „Leute, damit wir eure Anwendung starten Kubernetes, es sollte so sein.
Aus diesem Grund war die Präsentation so umfangreich. Entschuldigung. Ich werde versuchen, so viel wie möglich zu erzählen, damit es möglichst nicht langweilig wird.
Was wir uns jetzt ansehen werden:
- Dies sind erstens Protokolle (Anwendungsprotokolle?), was mit ihnen in Kubernetes zu tun ist, was mit ihnen zu tun ist, was sie sein sollten;
- Was ist mit Konfigurationen in Kubernetes zu tun? Was sind die besten und schlechtesten Möglichkeiten, eine Anwendung für Kubernetes zu konfigurieren?
- Lassen Sie uns darüber sprechen, was Barrierefreiheitsprüfungen im Allgemeinen sind und wie sie aussehen sollten.
- Lassen Sie uns darüber sprechen, was ein ordnungsgemäßes Herunterfahren ist.
- Lassen Sie uns noch einmal über Ressourcen sprechen.
- Kommen wir noch einmal zum Thema Datenspeicherung;
- und am Ende werde ich Ihnen sagen, wie diese mysteriöse Cloud-native-Anwendung bezeichnet wird. Cloudnativeness als Adjektiv dieses Begriffs.
Protokolle
Ich schlage vor, mit den Protokollen zu beginnen – mit der Stelle, an der diese Protokolle in Kubernetes abgelegt werden müssen. Jetzt haben Sie eine Anwendung in Kubernetes gestartet. Den Klassikern zufolge haben frühere Anwendungen Protokolle immer irgendwo in einer Datei geschrieben. Fehlerhafte Anwendungen haben Protokolle in eine Datei im Home-Verzeichnis des Entwicklers geschrieben, der die Anwendung gestartet hat. Gute Anwendungen haben Protokolle irgendwo in eine Datei geschrieben /var/log.

Dementsprechend haben gute Administratoren außerdem einige Dinge in ihren Infrastrukturen konfiguriert, damit diese Protokolle rotieren können – dasselbe rsyslog, das diese Protokolle überprüft, und wenn ihnen etwas passiert, gibt es viele davon, es erstellt Sicherungskopien und legt Protokolle dort ab , löscht alte Dateien, mehr als eine Woche, sechs Monate und einige mehr. Theoretisch sollten wir Vorkehrungen treffen, damit der Speicherplatz auf den Produktionsservern (Kampfservern?) nicht knapp wird, nur weil die Anwendung Protokolle schreibt. Und dementsprechend wurde die gesamte Produktion wegen der Protokolle nicht eingestellt.
Wenn wir in die Welt von Kubernetes wechseln und dort dasselbe ausführen, können Sie als Erstes darauf achten, dass die Leute, während sie Protokolle in eine Datei geschrieben haben, diese weiterhin schreiben.
Es stellt sich heraus, dass, wenn wir über Kubernetes sprechen, der richtige Ort zum Schreiben von Protokollen irgendwo aus einem Docker-Container einfach darin besteht, sie von der Anwendung in den sogenannten Stdout/Stderr zu schreiben, also in die Standardausgabeströme des Betriebssystems, den Standardfehler Ausgabe. Dies ist im Prinzip die korrekteste, einfachste und logischste Art, Protokolle in Docker und insbesondere in Kubernetis abzulegen. Denn wenn Ihre Anwendung Protokolle in Stdout/Stderr schreibt, liegt es an Docker und dem Kubernetes-Add-on, zu entscheiden, was mit diesen Protokollen geschehen soll. Docker erstellt seine speziellen Dateien standardmäßig im JSON-Format.
Hier stellt sich die Frage: Was machen Sie als nächstes mit diesen Protokollen? Der einfachste Weg ist klar, wir haben die Möglichkeit dazu kubectl logs und schauen Sie sich diese Protokolle dieser „Pods“ an. Aber wahrscheinlich ist dies keine sehr gute Option – mit den Protokollen muss etwas anderes gemacht werden.
Lassen Sie uns zunächst gleichzeitig darüber sprechen, wie Protokolle aussehen sollten, da wir bereits das Thema Protokolle angesprochen haben. Das gilt zwar nicht direkt für Kubernetes, aber wenn wir darüber nachdenken, was wir mit Protokollen machen sollen, wäre es gut, auch darüber nachzudenken.
Wir brauchen auf freundliche Weise eine Art Tool, das diese Protokolle, die unser Docker in seine Dateien einfügt, aufnimmt und irgendwohin sendet. Im Großen und Ganzen starten wir normalerweise eine Art Agent in Kubernetes in Form eines DaemonSets – eines Protokollsammlers, dem lediglich mitgeteilt wird, wo sich die von Docker gesammelten Protokolle befinden. Und dieser Sammler nimmt sie einfach, analysiert sie vielleicht sogar irgendwie nebenbei, reichert sie vielleicht mit einigen zusätzlichen Metainformationen an und schickt sie schließlich irgendwohin zur Speicherung. Variationen sind dort bereits möglich. Am gebräuchlichsten ist wahrscheinlich Elasticsearch, wo Sie Protokolle speichern und von dort bequem abrufen können. Erstellen Sie dann mithilfe einer Anfrage, beispielsweise mit Kibana, darauf basierende Diagramme, darauf basierende Warnungen usw.
Die wichtigste Idee, ich möchte sie noch einmal wiederholen, ist, dass es in Docker, insbesondere in Kubernetes, eine sehr schlechte Idee ist, Ihre Protokolle in einer Datei zu speichern.
Denn erstens ist es schwierig, die Protokolle in einer Datei im Container unterzubringen. Sie müssen zuerst in den Container gehen, dort ausführen und sich dann die Protokolle ansehen. Der nächste Punkt ist, dass, wenn Sie Protokolle in einer Datei haben, die Container normalerweise eine minimalistische Umgebung haben und es keine Dienstprogramme gibt, die normalerweise für die normale Arbeit mit Protokollen benötigt werden. Vergrabe sie, sieh sie dir an, öffne sie in einem Texteditor. Der nächste Moment ist, wenn wir Protokolle in einer Datei in einem Container haben. Wenn dieser Container gelöscht wird, werden natürlich auch die Protokolle gelöscht. Dementsprechend führt jeder Neustart des Containers dazu, dass keine Protokolle mehr vorhanden sind. Wieder eine schlechte Option.
Und der letzte Punkt ist, dass Sie in Containern normalerweise Ihre Anwendung haben und das war’s – es ist normalerweise der einzige Prozess, der ausgeführt wird. Von einem Prozess, der Dateien mit Ihren Protokollen rotieren würde, ist überhaupt keine Rede. Sobald die Protokolle in eine Datei geschrieben werden, bedeutet dies, entschuldigen Sie, dass wir beginnen, den Produktionsserver zu verlieren. Denn erstens sind sie schwer zu finden, niemand verfolgt sie und niemand kontrolliert sie – dementsprechend wächst die Datei endlos, bis der Platz auf dem Server einfach zur Neige geht. Deshalb sage ich noch einmal, dass es eine schlechte Idee ist, sich in Docker, insbesondere in Kubernetes, an einer Datei anzumelden.
Der nächste Punkt, hier möchte ich noch einmal darauf eingehen – da wir das Thema Protokolle ansprechen, wäre es gut, darüber zu sprechen, wie Protokolle aussehen sollten, um die Arbeit mit ihnen bequemer zu machen. Wie gesagt, das Thema hat nicht direkt mit Kubernetes zu tun, passt aber sehr gut zum Thema DevOps. Zum Thema Entwicklungskultur und Freundschaft zwischen diesen beiden verschiedenen Abteilungen – Dev und Ops, damit sich alle wohl fühlen.
Das bedeutet, dass Protokolle heute idealerweise im JSON-Format geschrieben werden sollten. Wenn Sie selbst eine unverständliche Anwendung haben, die Protokolle in unverständlichen Formaten schreibt, weil Sie eine Art Druck oder ähnliches einfügen, dann ist es an der Zeit, nach einer Art Framework, einer Art Wrapper zu googeln, mit dem Sie die normale Protokollierung implementieren können. Aktivieren Sie dort die Protokollierungsparameter in JSON, da JSON ein einfaches Format ist und das Parsen einfach ist.
Wenn Ihr JSON nach einigen Kriterien nicht funktioniert, niemand weiß was, dann schreiben Sie zumindest Protokolle in einem Format, das analysiert werden kann. Hier lohnt es sich vielmehr, darüber nachzudenken, dass es für Sie wahrscheinlich sehr unpraktisch sein wird, wenn Sie beispielsweise eine Reihe von Containern oder nur Prozesse mit Nginx ausführen und jeder seine eigenen Protokollierungseinstellungen hat Analysieren Sie sie. Denn für jede neue Nginx-Instanz müssen Sie Ihren eigenen Parser schreiben, da diese Protokolle unterschiedlich schreiben. Auch hier war es wahrscheinlich eine Überlegung wert, dafür zu sorgen, dass alle diese Nginx-Instanzen die gleiche Protokollierungskonfiguration haben und alle ihre Protokolle absolut einheitlich schreiben. Das Gleiche gilt für absolut alle Anwendungen.
Abschließend möchte ich auch noch Öl ins Feuer gießen, dass Protokolle im mehrzeiligen Format im Idealfall vermieden werden sollten. Hier ist die Sache: Wenn Sie jemals mit Protokollsammlern gearbeitet haben, dann haben Sie höchstwahrscheinlich gesehen, was sie Ihnen versprechen, dass sie mit mehrzeiligen Protokollen arbeiten können, wissen, wie man sie sammelt und so weiter. Tatsächlich kann meiner Meinung nach heute kein einziger Sammler mehrzeilige Protokolle normal, vollständig und fehlerfrei sammeln. Auf menschliche Weise, damit es bequem und fehlerfrei ist.

Beim Stacktrace handelt es sich jedoch immer um mehrzeilige Protokolle und wie man diese vermeidet. Die Frage hier ist, dass ein Protokoll eine Aufzeichnung eines Ereignisses ist und Stactrace eigentlich kein Protokoll ist. Wenn wir Protokolle sammeln und sie irgendwo in Elasticsearch ablegen und dann Diagramme daraus erstellen, einige Berichte über Benutzeraktivitäten auf Ihrer Website erstellen, bedeutet das, dass Sie einen Stack-Trace erhalten, dass etwas Unerwartetes passiert. Eine unbehandelte Situation in Ihrer Anwendung. Und es ist sinnvoll, einen Stack-Trace automatisch irgendwo in ein System hochzuladen, das sie verfolgen kann.
Dabei handelt es sich um Software (derselbe Sentry), die speziell für die Arbeit mit Stacktrace entwickelt wurde. Es kann sofort automatisierte Aufgaben erstellen, sie jemandem zuweisen, eine Warnung ausgeben, wenn Stacttraces auftreten, diese Stacttraces nach einem Typ gruppieren und so weiter. Im Prinzip macht es wenig Sinn, von Stactraces zu sprechen, wenn wir von Protokollen sprechen, denn es handelt sich schließlich um unterschiedliche Dinge mit unterschiedlichen Zwecken.
Konfiguration
Als nächstes sprechen wir über die Konfiguration in Kubernetes: was damit zu tun ist und wie Anwendungen in Kubernetes konfiguriert werden sollten. Im Allgemeinen sage ich normalerweise, dass es bei Docker nicht um Container geht. Jeder weiß, dass es bei Docker um Container geht, auch diejenigen, die noch nicht viel mit Docker gearbeitet haben. Ich wiederhole: Bei Docker geht es nicht um Container.
Bei Docker geht es meiner Meinung nach um Standards. Und es gibt Standards für praktisch alles: Standards für die Erstellung Ihrer Anwendung, Standards für die Installation Ihrer Anwendung.

Und dieses Ding – wir haben es früher verwendet, es wurde erst mit dem Aufkommen von Containern besonders beliebt – dieses Ding nennt sich ENV-Variablen (Umgebungsvariablen), also Umgebungsvariablen, die sich in Ihrem Betriebssystem befinden. Dies ist im Allgemeinen eine ideale Möglichkeit, Ihre Anwendung zu konfigurieren, denn wenn Sie Anwendungen in JAVA, Python, Go, Perl, Gott bewahre, haben und diese alle die Datenbankhost-, Datenbankbenutzer- und Datenbankkennwortvariablen lesen können, dann ist dies ideal. Sie haben im Datenbankplan auf die gleiche Weise Anwendungen in vier verschiedenen Sprachen konfiguriert. Es gibt keine unterschiedlichen Konfigurationen mehr.
Alles kann mithilfe von ENV-Variablen konfiguriert werden. Wenn wir über Kubernetes sprechen, gibt es eine großartige Möglichkeit, ENV-Variablen direkt in der Bereitstellung zu deklarieren. Wenn es sich also um geheime Daten handelt, können wir geheime Daten aus ENV-Variablen (Passwörter für Datenbanken usw.) sofort in ein Geheimnis verschieben, einen geheimen Cluster erstellen und in der ENV-Beschreibung im Deployment angeben, dass wir nicht direkt deklarieren Der Wert dieser Variablen und der Wert dieser Datenbankkennwortvariablen werden aus dem Geheimnis gelesen. Dies ist das Standardverhalten von Kubernetes. Und dies ist die idealste Option zur Konfiguration Ihrer Anwendungen. Nur auf Codeebene gilt dies wiederum für Entwickler. Wenn Sie DevOps sind, können Sie fragen: „Leute, bitte bringen Sie Ihrer Anwendung bei, Umgebungsvariablen zu lesen.“ Und wir werden alle glücklich sein.“
Wenn jeder im Unternehmen die gleichnamigen Umgebungsvariablen liest, ist das großartig. Damit es nicht passiert, dass einige auf die Postgres-Datenbank warten, andere auf den Datenbanknamen, andere auf etwas anderes, wieder andere auf irgendeine Art von Datenbank, damit dementsprechend Einheitlichkeit herrscht.
Das Problem entsteht, wenn Sie so viele Umgebungsvariablen haben, dass Sie einfach „Deployment“ öffnen – und es fünfhundert Zeilen mit Umgebungsvariablen gibt. In diesem Fall sind Sie den Umgebungsvariablen einfach entwachsen – und müssen sich nicht mehr quälen. In diesem Fall wäre es sinnvoll, mit der Verwendung von Konfigurationen zu beginnen. Das heißt, trainieren Sie Ihre Anwendung für die Verwendung von Konfigurationen.
Die einzige Frage ist, dass die Konfigurationen nicht Ihren Vorstellungen entsprechen. Config.pi ist keine Konfiguration, die bequem zu verwenden ist. Oder eine Konfiguration im eigenen Format, alternativ geschenkt – das ist auch nicht die Konfiguration, die ich meine.
Ich spreche von der Konfiguration in akzeptablen Formaten, das heißt, der mit Abstand beliebteste Standard ist der .yaml-Standard. Es ist klar, wie man es liest, es ist für Menschen lesbar, es ist klar, wie man es aus der Anwendung heraus liest.
Dementsprechend können Sie neben YAML beispielsweise auch JSON verwenden, das Parsen ist in etwa so komfortabel wie YAML, was das Auslesen der Anwendungskonfiguration von dort angeht. Das Lesen ist für die Menschen spürbar unbequemer. Sie können das Format a la ini ausprobieren. Aus menschlicher Sicht ist es recht bequem zu lesen, aber es kann unbequem sein, es automatisch zu verarbeiten, in dem Sinne, dass, wenn Sie jemals Ihre eigenen Konfigurationen generieren möchten, das INI-Format möglicherweise bereits unbequem zu generieren ist.
Unabhängig davon, welches Format Sie wählen, ist es aus Kubernetes-Sicht jedoch sehr praktisch. Sie können Ihre gesamte Konfiguration in Kubernetes in der ConfigMap ablegen. Und dann nehmen Sie diese Konfigurationskarte und bitten Sie sie, sie in Ihrem Pod in einem bestimmten Verzeichnis bereitzustellen, wo Ihre Anwendung die Konfiguration aus dieser Konfigurationskarte liest, als wäre es nur eine Datei. Dies ist in der Tat sinnvoll, wenn Ihre Anwendung über viele Konfigurationsoptionen verfügt. Oder es handelt sich einfach um eine komplexe Struktur, es gibt eine Verschachtelung.
Wenn Sie über eine Configmap verfügen, können Sie Ihrer Anwendung sehr gut beibringen, beispielsweise automatisch Änderungen in der Datei zu verfolgen, in der die Configmap gemountet ist, und Ihre Anwendung auch automatisch neu zu laden, wenn sich die Konfigurationen ändern. Dies wäre im Allgemeinen eine ideale Option.
Auch hierüber habe ich bereits gesprochen – geheime Informationen befinden sich nicht in der Konfigurationskarte, geheime Informationen befinden sich nicht in Variablen, geheime Informationen befinden sich nicht in Geheimnissen. Von dort aus verbinden Sie diese geheimen Informationen mit der Diplomatie. Normalerweise speichern wir alle Beschreibungen von Kubernetes-Objekten, Bereitstellungen, Konfigurationskarten und Diensten in Git. Dementsprechend ist es eine schlechte Idee, das Passwort für die Datenbank in Git einzugeben, selbst wenn es Ihr Git ist, den Sie intern im Unternehmen haben. Denn zumindest merkt sich Git alles und es ist nicht so einfach, Passwörter von dort zu entfernen.
Gesundheitskontrolle
Der nächste Punkt ist die sogenannte Gesundheitsprüfung. Im Allgemeinen wird bei einem Health Check lediglich überprüft, ob Ihre Anwendung funktioniert. Dabei handelt es sich am häufigsten um bestimmte Webanwendungen, bei denen es sich dementsprechend aus Sicht der Gesundheitsprüfung (es ist besser, hier und weiter nicht zu übersetzen) um eine spezielle URL handelt, die sie als verarbeiten ein Standard, das tun sie normalerweise /health.
Beim Zugriff auf diese URL sagt unsere Anwendung dementsprechend entweder „Ja, okay, bei mir ist alles in Ordnung, 200“ oder „Nein, bei mir ist nicht alles in Ordnung, etwa 500“. Wenn unsere Anwendung also kein http und keine Webanwendung ist, sprechen wir jetzt von einer Art Daemon, mit dem wir herausfinden können, wie Gesundheitsprüfungen durchgeführt werden. Das heißt, es ist nicht notwendig, wenn die Anwendung nicht http ist, dann funktioniert alles ohne Gesundheitsprüfung und dies ist in keiner Weise möglich. Sie können einige Informationen in der Datei regelmäßig aktualisieren und einen speziellen Befehl für Ihren Daemon erstellen, z. B. daemon status, was sagen wird: „Ja, alles ist in Ordnung, der Daemon funktioniert, er lebt.“
Wofür ist das? Der erste und offensichtlichste Grund ist wahrscheinlich, warum eine Gesundheitsprüfung erforderlich ist – um zu verstehen, dass die Anwendung funktioniert. Ich meine, es ist einfach nur dumm, wenn es jetzt online ist, sieht es so aus, als würde es funktionieren, also können Sie sicher sein, dass es funktioniert. Und es stellt sich heraus, dass die Anwendung läuft, der Container läuft, die Instanz funktioniert, alles in Ordnung ist – und dann haben die Benutzer bereits alle Telefonnummern vom technischen Support abgeschnitten und sagen: „Was sind Sie ..., Sie?“ eingeschlafen, nichts geht.“
Ein Gesundheitscheck ist eine solche Möglichkeit, aus Benutzersicht zu sehen, ob es funktioniert. Eine der Methoden. Sagen wir mal so. Aus Sicht von Kubernetes ist dies auch eine Möglichkeit zu verstehen, wann die Anwendung gestartet wird, da wir verstehen, dass es einen Unterschied zwischen dem Start, der Erstellung und dem Start des Containers und dem direkten Start der Anwendung in diesem Container gibt. Denn wenn wir eine durchschnittliche Java-Anwendung nehmen und versuchen, sie im Dock zu starten, kann sie innerhalb von vierzig Sekunden oder sogar einer Minute oder sogar zehn Sekunden problemlos starten. In diesem Fall können Sie zumindest an seinen Ports klopfen, er antwortet dort nicht, das heißt, er ist noch nicht bereit, Datenverkehr zu empfangen.
Auch hier können wir mit Hilfe eines Health Checks und mit Hilfe der Tatsache, dass wir uns hier umdrehen, in Kubernetes nachvollziehen, dass nicht nur der Container in der Anwendung aufgestiegen ist, sondern die Anwendung selbst gestartet wurde, sie bereits auf die reagiert Gesundheitscheck, was bedeutet, dass wir Datenverkehr dorthin senden können.

Ich spreche jetzt von sogenannten Readiness/Liveness-Tests innerhalb von Kubernetes; dementsprechend sind unsere Readiness-Tests für die Verfügbarkeit der Anwendung im Balancing verantwortlich. Das heißt, wenn in der Anwendung Bereitschaftstests durchgeführt werden, ist alles in Ordnung, der Clientverkehr wird an die Anwendung weitergeleitet. Wenn keine Bereitschaftstests durchgeführt werden, nimmt die Anwendung einfach nicht teil, diese bestimmte Instanz nimmt nicht am Balancing teil, sie wird aus dem Balancing entfernt, der Client-Verkehr fließt nicht. Dementsprechend sind Liveness-Tests innerhalb von Kubernetes erforderlich, damit die Anwendung neu gestartet werden kann, wenn sie hängen bleibt. Wenn der Liveness-Test für eine in Kubernetes deklarierte Anwendung nicht funktioniert, wird die Anwendung nicht nur aus dem Balancing entfernt, sondern neu gestartet.
Und hier möchte ich noch einen wichtigen Punkt erwähnen: Aus praktischer Sicht wird der Readiness-Test in der Regel häufiger eingesetzt und benötigt als der Liveness-Test. Das heißt, einfach gedankenlos sowohl Bereitschafts- als auch Liveness-Tests zu deklarieren, weil Kubernetes das kann, und nutzen wir alles, was es kann, ist keine sehr gute Idee. Ich werde erklären, warum. Denn Punkt zwei beim Testen ist, dass es eine gute Idee wäre, den zugrunde liegenden Dienst in Ihren Gesundheitschecks zu überprüfen. Das heißt, wenn Sie über eine Webanwendung verfügen, die einige Informationen ausgibt, muss diese diese wiederum natürlich von irgendwoher beziehen. Zum Beispiel in einer Datenbank. Nun, es speichert die Informationen, die in diese REST-API eingehen, in derselben Datenbank. Wenn Ihr Gesundheitscheck dann einfach wie bei der Kontaktaufnahme mit slashhealth antwortet, sagt die Anwendung „200, okay, alles ist in Ordnung“, und gleichzeitig ist die Datenbank Ihrer Anwendung nicht zugänglich, und die Gesundheitscheck-Anwendung sagt „200, okay, alles ist in Ordnung.“ ” – Das ist ein schlechter Gesundheitscheck. So sollte es nicht funktionieren.
Das heißt, Ihre Bewerbung, wenn eine Anfrage dazu kommt /health, es antwortet nicht nur „200, ok“, es geht zunächst zum Beispiel zur Datenbank, versucht, eine Verbindung zu ihr herzustellen, macht dort etwas ganz Grundlegendes, wie zum Beispiel „Eine auswählen“, prüft einfach, ob eine Verbindung in der Datenbank besteht Datenbank und Sie können die Datenbank abfragen. Wenn das alles erfolgreich war, lautet die Antwort „200, ok.“ Wenn dies nicht erfolgreich ist, heißt es, dass ein Fehler vorliegt und die Datenbank nicht verfügbar ist.
Daher komme ich in diesem Zusammenhang noch einmal auf die Bereitschafts-/Lebendigkeitstests zurück – weshalb Sie höchstwahrscheinlich einen Bereitschaftstest benötigen, ein Lebendigkeitstest jedoch in Frage kommt. Denn wenn man Health Checks genau so beschreibt, wie ich es gerade gesagt habe, dann stellt sich heraus, dass sie im Instanzteil nicht verfügbar sindв или со всех instancezum Beispiel in einer Datenbank. Als Sie einen Bereitschaftstest erklärten, begannen unsere Integritätsprüfungen fehlzuschlagen, und dementsprechend wurden alle Anwendungen, von denen aus nicht auf die Datenbank zugegriffen werden kann, einfach vom Balancing abgeschaltet und „hängen“ tatsächlich einfach in einem vernachlässigten Zustand und warten darauf, dass ihre Datenbanken funktionieren arbeiten.
Wenn wir einen Liveness-Test deklariert haben, dann stellen Sie sich vor, unsere Datenbank ist kaputt und in Ihrem Kubernetes beginnt die Hälfte von allem neu zu starten, weil der Liveness-Test fehlschlägt. Das bedeutet, dass Sie neu starten müssen. Das ist überhaupt nicht das, was Sie wollen, ich habe sogar persönliche Erfahrungen in der Praxis gemacht. Wir hatten eine Chat-Anwendung, die in JS geschrieben und in eine Mongo-Datenbank eingespeist wurde. Und das Problem war, dass wir zu Beginn meiner Arbeit mit Kubernetes die Bereitschaft und Lebendigkeit von Tests auf der Grundlage beschrieben haben, dass Kubernetes dies kann, also werden wir es verwenden. Dementsprechend wurde Mongo irgendwann etwas „langweilig“ und die Probe begann zu versagen. Demnach begannen die Schoten laut Regentest zu „töten“.
Wie Sie wissen, handelt es sich beim „Töten“ um einen Chat, das heißt, es hängen viele Verbindungen von Kunden daran. Sie werden auch „getötet“ – nein, keine Clients, nur Verbindungen – nicht alle gleichzeitig, und aufgrund der Tatsache, dass sie nicht gleichzeitig getötet werden, einige früher, andere später, starten sie nicht gleichzeitig Zeit. Zusätzlich zum Standardzufallsprinzip können wir die Startzeit der Anwendung nicht jedes Mal mit Millisekundengenauigkeit vorhersagen, daher wird dies jeweils für eine Instanz durchgeführt. Ein Infospot steigt, wird zum Ausgleich hinzugefügt, alle Kunden kommen dorthin, er kann einer solchen Belastung nicht standhalten, weil er allein ist, und grob gesagt arbeiten dort ein Dutzend von ihnen, und er fällt. Der nächste steigt, die ganze Last lastet auf ihm, auch er fällt. Nun ja, diese Stürze gehen einfach weiter. Letztendlich wurde das Problem gelöst: Wir mussten lediglich den Benutzerverkehr zu dieser Anwendung strikt stoppen, alle Instanzen hochfahren lassen und dann den gesamten Benutzerverkehr auf einmal starten, sodass er bereits auf alle zehn Instanzen verteilt wurde.
Wenn dieser Liveness-Test nicht angekündigt worden wäre, der einen Neustart erzwingen würde, hätte die Anwendung das problemlos gemeistert. Aber alles vom Balancing ist für uns deaktiviert, da auf die Datenbanken nicht zugegriffen werden kann und alle Benutzer „abgefallen“ sind. Wenn diese Datenbank dann verfügbar ist, ist alles im Balancing enthalten, aber die Anwendungen müssen nicht erneut gestartet werden und es besteht keine Notwendigkeit, Zeit und Ressourcen dafür zu verschwenden. Sie sind alle schon da, sie sind bereit für den Verkehr, der Verkehr wird also gerade erst freigegeben, alles ist in Ordnung – die Anwendung ist vorhanden, alles funktioniert weiterhin.
Daher sind Bereitschafts- und Lebendigkeitstests unterschiedlich. Darüber hinaus können Sie theoretisch unterschiedliche Gesundheitsprüfungen durchführen, beispielsweise einen Radientyp, einen Liv-Typ und verschiedene Dinge überprüfen. Überprüfen Sie während der Bereitschaftstests Ihre Backends. Und bei einem Liveness-Test überprüfen Sie beispielsweise nicht unter dem Gesichtspunkt, dass es sich bei dem Liveness-Test im Allgemeinen nur um eine antwortende Anwendung handelt, wenn sie überhaupt in der Lage ist, zu antworten.
Denn der Lebendigkeitstest findet im Großen und Ganzen dann statt, wenn wir „feststecken“. Eine Endlosschleife hat begonnen oder etwas anderes – und es werden keine Anfragen mehr bearbeitet. Daher ist es sinnvoll, sie sogar zu trennen – und unterschiedliche Logik in ihnen zu implementieren.
Was Sie bei einem Test und bei Gesundheitschecks beantworten müssen. Es ist einfach wirklich schmerzhaft. Wer sich damit auskennt, wird wahrscheinlich lachen – aber im Ernst, ich habe in meinem Leben Dienste gesehen, die in 200 % der Fälle mit „XNUMX“ antworten. Das heißt, wer erfolgreich ist. Aber gleichzeitig schreiben sie im Hauptteil der Antwort „so und so ein Fehler.“
Das heißt, der Antwortstatus kommt zu Ihnen – alles ist erfolgreich. Aber gleichzeitig müssen Sie den Körper analysieren, da der Körper sagt: „Entschuldigung, die Anfrage wurde mit einem Fehler beendet“, und das ist nur die Realität. Ich habe das im wirklichen Leben gesehen.
Und damit es manche nicht lustig und andere sehr schmerzhaft finden, lohnt es sich trotzdem, sich an eine einfache Regel zu halten. Bei Gesundheitschecks und grundsätzlich bei der Arbeit mit Webanwendungen.
Wenn alles gut gelaufen ist, antworten Sie mit der zweihundertsten Antwort. Im Prinzip passt jede zweihundertste Antwort zu Ihnen. Wenn Sie Ragsy sehr gut lesen und wissen, dass sich einige Antwortstatus von anderen unterscheiden, antworten Sie mit den entsprechenden: 204, 5, 10, 15, was auch immer. Wenn es nicht sehr gut ist, dann einfach „zwei null null“. Wenn alles schief geht und der Gesundheitscheck nicht reagiert, dann antworten Sie mit einem beliebigen Fünfhundertstel. Auch hier gilt: Wenn Sie verstehen, wie man reagiert, wie sich die verschiedenen Antwortstatus voneinander unterscheiden. Wenn Sie es nicht verstehen, ist 502 Ihre Option, um auf Gesundheitschecks zu reagieren, wenn etwas schief geht.
Dies ist ein weiterer Punkt. Ich möchte kurz auf die Überprüfung der zugrunde liegenden Dienste zurückkommen. Wenn Sie beispielsweise damit beginnen, alle zugrunde liegenden Dienste zu überprüfen, die hinter Ihrer Anwendung stehen – alles im Allgemeinen. Was wir aus der Sicht der Microservice-Architektur erhalten, ist, dass wir ein Konzept wie „geringe Kopplung“ haben – das heißt, wenn Ihre Dienste nur minimal voneinander abhängig sind. Fällt einer von ihnen aus, funktionieren alle anderen ohne diese Funktionalität einfach weiter. Einige Funktionen funktionieren einfach nicht. Соответственно, если вы все хэлсчеки завяжете друг на друга, то у вас получится, что в инфраструктуре упало что-то одно, а из-за того, что оно упало, все хэлсчеки всех сервисов тоже начинают фэйлиться — и инфраструктуры вообще всей микросервисной архитектуры больше Nein. Dort wurde alles dunkel.
Deshalb möchte ich noch einmal wiederholen, dass Sie die zugrunde liegenden Dienste überprüfen müssen, ohne die Ihre Anwendung in hundert Prozent der Fälle ihre Aufgabe nicht erfüllen kann. Das heißt, es ist logisch, dass Sie die Arbeit mit Ihren Benutzern nicht garantieren können, wenn Sie über eine REST-API verfügen, über die der Benutzer in der Datenbank speichert oder aus der Datenbank abruft. Wenn keine Datenbank vorhanden ist, können Sie die Arbeit mit Ihren Benutzern nicht garantieren.
Wenn Ihre Benutzer jedoch beim Herausnehmen aus der Datenbank zusätzlich mit einigen anderen Metadaten aus einem anderen Backend angereichert werden, die Sie eingeben, bevor Sie eine Antwort an das Frontend senden – und dieses Backend nicht verfügbar ist, bedeutet dies, dass Sie Ihre angeben Antwort ohne einen Teil der Metadaten.
Als nächstes haben wir auch eines der schmerzhaften Probleme beim Starten von Anwendungen.
Tatsächlich gilt dies nicht nur für Kubernetes im Großen und Ganzen; es ist einfach so, dass sich etwa zur gleichen Zeit wie Kubernetes die Kultur einer Art Massenentwicklung und insbesondere von DevOps zu verbreiten begann. Daher stellt sich im Großen und Ganzen heraus, dass Sie Ihre Anwendung ohne Kubernetes ordnungsgemäß herunterfahren müssen. Schon vor Kubernetes haben die Leute das gemacht, aber mit dem Aufkommen von Kubernetes haben wir angefangen, massenhaft darüber zu reden.
Anmutiges Herunterfahren
Was ist Graceful Shutdown im Allgemeinen und warum wird es benötigt? Hier geht es darum, dass Sie dies tun müssen, wenn Ihre Anwendung aus irgendeinem Grund abstürzt app stop - oder Sie erhalten beispielsweise ein Signal vom Betriebssystem, Ihre Anwendung muss es verstehen und etwas dagegen unternehmen. Das schlimmste Szenario ist natürlich, wenn Ihre Bewerbung ein SIGTERM erhält und sagt: „SIGTERM, lass uns durchhalten, arbeiten, nichts tun.“ Das ist eine ausgesprochen schlechte Option.

Eine fast ebenso schlechte Option ist, wenn Ihre Anwendung ein SIGTERM erhält und sagt: „Sie haben Segterm gesagt, das heißt, wir enden, ich habe keine Benutzeranfragen gesehen, ich kenne sie nicht, ich weiß nicht, welche Art von.“ Anfragen, an denen ich gerade arbeite, sagten sie SIGTERM, das bedeutet, dass wir Schluss machen. Auch das ist eine schlechte Option.
Welche Option ist gut? Der erste Punkt besteht darin, den Abschluss der Operationen zu berücksichtigen. Eine gute Option besteht darin, dass Ihr Server weiterhin berücksichtigt, was er tut, wenn er ein SIGTERM empfängt.
SIGTERM ist ein sanftes Herunterfahren, es ist speziell entwickelt, es kann auf Codeebene abgefangen und verarbeitet werden. Sagen Sie jetzt, warten Sie, wir beenden zuerst die Arbeit, die wir haben, und beenden dann den Vorgang.
Aus Kubernetes-Perspektive sieht es so aus. Wenn wir zu einem Pod, der im Kubernetes-Cluster ausgeführt wird, sagen: „Bitte stoppen Sie, gehen Sie weg“, oder wenn wir neu gestartet werden oder ein Update erfolgt, wenn Kubernetes die Pods neu erstellt, sendet Kubernetes genau dieselbe SIGTERM-Nachricht an den Pod und wartet darauf einige Zeit, und das ist die Zeit, die er wartet, es ist auch konfiguriert, es gibt so einen speziellen Parameter in Diplomen und er heißt Graceful ShutdownTimeout. Wie Sie wissen, heißt es nicht umsonst so, und nicht umsonst reden wir jetzt darüber.
Dort können wir konkret sagen, wie lange wir zwischen dem Senden von SIGTERM an die Anwendung und dem Zeitpunkt, an dem wir feststellen, dass die Anwendung verrückt geworden zu sein scheint oder „steckengeblieben“ ist und nicht enden wird, warten müssen – und das müssen wir tun Senden Sie ihm SIGKILL, das heißt, schließen Sie seine Arbeit hart ab. Das heißt, bei uns läuft dementsprechend eine Art Daemon, der Vorgänge verarbeitet. Uns ist bewusst, dass unsere Vorgänge, an denen der Daemon arbeitet, im Durchschnitt nicht länger als 30 Sekunden am Stück dauern. Wenn SIGTERM eintrifft, gehen wir davon aus, dass unser Daemon höchstens 30 Sekunden nach SIGTERM fertig sein kann. Wir schreiben es zum Beispiel für alle Fälle 45 Sekunden und sagen das SIGTERM. Danach warten wir 45 Sekunden. Theoretisch hätte der Dämon in dieser Zeit seine Arbeit abschließen und sich selbst beenden sollen. Wenn dies jedoch plötzlich nicht mehr möglich ist, bedeutet dies höchstwahrscheinlich, dass es feststeckt – es verarbeitet unsere Anfragen nicht mehr normal. Und in 45 Sekunden können Sie ihn tatsächlich sicher festnageln.
Und hier können tatsächlich sogar 2 Aspekte berücksichtigt werden. Verstehen Sie zunächst, dass Sie, wenn Sie eine Anfrage erhalten haben, irgendwie mit der Arbeit begonnen haben und dem Benutzer keine Antwort gegeben haben, sondern beispielsweise SIGTERM erhalten haben. Es ist sinnvoll, es zu verfeinern und dem Benutzer eine Antwort zu geben. Dies ist in dieser Hinsicht Punkt Nummer eins. Punkt Nummer zwei hier ist: Wenn Sie Ihre eigene Anwendung schreiben, bauen Sie die Architektur im Allgemeinen so auf, dass Sie eine Anfrage für Ihre Anwendung erhalten, dann beginnen Sie mit der Arbeit, beginnen mit dem Herunterladen von Dateien von irgendwoher, dem Herunterladen einer Datenbank und so weiter. - Das. Im Allgemeinen bleibt Ihr Benutzer mit Ihrer Anfrage eine halbe Stunde lang hängen und wartet darauf, dass Sie ihm antworten. Dann müssen Sie höchstwahrscheinlich an der Architektur arbeiten. Das heißt, berücksichtigen Sie einfach den gesunden Menschenverstand, dass es bei kurzen Operationen sinnvoll ist, SIGTERM zu ignorieren und zu ändern. Wenn Ihre Operationen langwierig sind, macht es in diesem Fall keinen Sinn, SIGTERM zu ignorieren. Es ist sinnvoll, die Architektur neu zu gestalten, um solch lange Vorgänge zu vermeiden. Damit Benutzer nicht nur herumhängen und warten. Ich weiß nicht, erstellen Sie dort eine Art Websocket, erstellen Sie Reverse-Hooks, die Ihr Server bereits an den Client sendet, irgendetwas anderes, aber zwingen Sie den Benutzer nicht, eine halbe Stunde lang zu hängen und warten Sie einfach auf eine Sitzung, bis Sie antworte ihm. Weil es unvorhersehbar ist, wo es kaputt gehen könnte.
Wenn Ihre Anwendung beendet wird, sollten Sie einen geeigneten Exit-Code angeben. Das heißt, wenn Ihre Anwendung zum Schließen und Stoppen aufgefordert wurde und sie sich normal stoppen konnte, müssen Sie keinen Exit-Code 1,5,255 usw. zurückgeben. Alles, was kein Nullcode ist, gilt zumindest in Linux-Systemen, da bin ich mir sicher, als erfolglos. Das heißt, es wird davon ausgegangen, dass Ihre Bewerbung in diesem Fall mit einem Fehler endete. Wenn Ihre Bewerbung fehlerfrei abgeschlossen wurde, sagen Sie dementsprechend auf einvernehmliche Weise 0 in der Ausgabe. Wenn Ihre Anwendung aus irgendeinem Grund fehlschlägt, geben Sie in der Ausgabe ungleich 0 an. Und Sie können mit diesen Informationen arbeiten.
Und die letzte Option. Es ist schlimm, wenn Ihr Benutzer eine Anfrage sendet und eine halbe Stunde lang hängen bleibt, während Sie sie verarbeiten. Generell möchte ich aber auch sagen, was sich aus Kundensicht grundsätzlich lohnt. Es spielt keine Rolle, ob Sie eine mobile Anwendung, ein Frontend usw. haben. Es ist zu berücksichtigen, dass die Sitzung des Benutzers im Allgemeinen beendet werden kann und alles passieren kann. Beispielsweise kann es vorkommen, dass eine Anfrage unzureichend verarbeitet wird und keine Antwort zurückgegeben wird. Ihr Frontend oder Ihre mobile Anwendung – sagen wir mal so: jedes Frontend im Allgemeinen – sollte dies berücksichtigen. Wenn Sie mit Websockets arbeiten, ist dies im Allgemeinen der schlimmste Schmerz, den ich je hatte.
Wenn die Entwickler einiger regulärer Chats das nicht wissen, kann es passieren, dass der Websocket kaputt geht. Wenn beim Proxy etwas passiert, ändern wir einfach die Konfiguration und es wird ein Neuladen durchgeführt. Natürlich werden in diesem Fall alle langlebigen Sitzungen unterbrochen. Entwickler kommen zu uns gerannt und sagen: „Leute, was macht ihr da, der Chat ist für alle unsere Kunden zusammengebrochen!“ Wir sagen ihnen: „Was machst du? Können Ihre Kunden die Verbindung nicht wiederherstellen? Sie sagen: „Nein, wir brauchen, dass die Sitzungen nicht zerrissen werden.“ Kurz gesagt, das ist eigentlich Unsinn. Die Clientseite muss berücksichtigt werden. Wie gesagt, insbesondere bei langlebigen Sitzungen wie Websockets kann es zu Unterbrechungen kommen, und Sie müssen in der Lage sein, solche Sitzungen unbemerkt vom Benutzer neu zu installieren. Und dann ist alles perfekt.
Ressourcen
Eigentlich erzähle ich Ihnen hier nur eine klare Geschichte. Wieder aus dem wahren Leben. Das Schlimmste, was ich je über Ressourcen gehört habe.
Mit Ressourcen meine ich in diesem Fall eine Art Anfragen, Beschränkungen, die Sie Pods in Ihren Kubernetes-Clustern auferlegen können. Das Witzigste, was ich von einem Entwickler gehört habe ... Einer meiner Entwicklerkollegen an einem früheren Arbeitsplatz sagte einmal: „Meine Anwendung startet nicht im Cluster.“ Ich sah nach, dass es nicht startete, aber entweder passte es nicht in die Ressourcen, oder sie hatten sehr kleine Grenzen gesetzt. Kurz gesagt: Die Anwendung kann aufgrund von Ressourcenmangel nicht gestartet werden. Ich sage: „Aus Ressourcengründen geht es nicht los, Sie entscheiden, wie viel Sie benötigen und legen einen angemessenen Wert fest.“ Er sagt: „Was für Ressourcen?“ Ich fing an, ihm zu erklären, dass Kubernetes, Beschränkungen für Anfragen und bla, bla, bla festgelegt werden müssen. Der Mann hörte fünf Minuten lang zu, nickte und sagte: „Ich bin hierher gekommen, um als Entwickler zu arbeiten, ich möchte nichts über irgendwelche Ressourcen wissen.“ Ich bin hierher gekommen, um Code zu schreiben, und das war’s.“ Es ist traurig. Aus Entwicklersicht ist das ein sehr trauriges Konzept. Besonders in der modernen Welt sozusagen fortschrittlicher Entwickler.
Warum werden überhaupt Ressourcen benötigt? Es gibt zwei Arten von Ressourcen in Kubernetes. Einige werden als Anfragen bezeichnet, andere als Limits. Unter Ressourcen verstehen wir, dass es grundsätzlich immer nur zwei grundlegende Einschränkungen gibt. Das heißt, CPU-Zeitlimits und RAM-Limits für einen Container, der in Kubernetes ausgeführt wird.
Ein Limit legt eine Obergrenze dafür fest, wie eine Ressource in Ihrer Anwendung verwendet werden kann. Das heißt, wenn Sie als Grenzwerte 1 GB RAM angeben, kann Ihre Anwendung nicht mehr als 1 GB RAM verwenden. Und wenn er dies plötzlich will und versucht, kommt ein Prozess namens Oom-Killer, der nicht mehr im Speicher ist und Ihre Anwendung beendet – das heißt, sie wird einfach neu gestartet. Anwendungen werden basierend auf der CPU nicht neu gestartet. Was die CPU anbelangt: Wenn eine Anwendung versucht, viel zu nutzen, mehr als in den Grenzwerten angegeben, wird die CPU einfach streng ausgewählt. Dies führt nicht zu Neustarts. Das ist die Grenze – das ist die Obergrenze.
Und es gibt eine Bitte. Eine Anfrage gibt an, wie Kubernetes versteht, wie die Knoten in Ihrem Kubernetes-Cluster mit Anwendungen gefüllt sind. Das heißt, eine Anfrage ist eine Art Commit Ihrer Anwendung. Dort steht, was ich nutzen möchte: „Ich möchte, dass Sie so viel CPU und so viel Speicher für mich reservieren.“ So eine einfache Analogie. Was wäre, wenn wir einen Knoten hätten, der, ich weiß nicht, insgesamt 8 CPUs hat? Und dort kommt ein Pod an, dessen Anfragen 1 CPU besagen, was bedeutet, dass der Knoten noch 7 CPUs übrig hat. Das heißt, sobald 8 Pods an diesem Knoten ankommen, von denen jeder 1 CPU in seinen Anfragen hat, ist dem Knoten, als ob aus Sicht von Kubernetes die CPU ausgegangen wäre, und weitere Pods mit Anfragen nicht möglich auf diesem Knoten gestartet. Wenn allen Knoten die CPU ausgeht, meldet Kubernetes, dass im Cluster keine geeigneten Knoten zum Ausführen Ihrer Pods vorhanden sind, da die CPU erschöpft ist.
Warum werden Anfragen benötigt und warum besteht meiner Meinung nach keine Notwendigkeit, in Kubernetes etwas ohne Anfragen zu starten? Stellen wir uns eine hypothetische Situation vor. Sie starten Ihre Anwendung ohne Anfragen. Kubernetes weiß nicht, wie viel von dem, was Sie haben, und auf welche Knoten Sie es übertragen können. Nun, er schiebt, schiebt, schiebt auf die Knoten. Irgendwann werden Sie Traffic auf Ihre Anwendung bekommen. Und plötzlich beginnt eine der Anwendungen, Ressourcen bis zu den Grenzen zu verbrauchen, die ihr gemäß den Grenzwerten zur Verfügung stehen. Es stellt sich heraus, dass sich in der Nähe eine andere Anwendung befindet, die ebenfalls Ressourcen benötigt. Dem Knoten gehen tatsächlich physisch die Ressourcen aus, zum Beispiel OP. Dem Knoten gehen tatsächlich physisch die Ressourcen aus, beispielsweise der Arbeitsspeicher (RAM). Wenn einem Knoten der Strom ausgeht, reagiert zunächst der Docker nicht mehr, dann das Cubelet und dann das Betriebssystem. Sie werden einfach bewusstlos und ALLES wird definitiv nicht mehr für Sie funktionieren. Das heißt, dies führt dazu, dass Ihr Knoten hängen bleibt und Sie ihn neu starten müssen. Kurz gesagt, die Situation ist nicht sehr gut.
Und wenn Sie Anfragen haben, sind die Grenzwerte nicht sehr unterschiedlich, zumindest nicht um ein Vielfaches größer als die Grenzwerte oder Anforderungen, dann können Sie eine so normale, rationelle Befüllung von Anwendungen über die Knoten von Kubernetes-Clustern hinweg erreichen. Gleichzeitig weiß Kubernetes ungefähr, wie viel von dem, was es wo ablegt, wie viel, was wo verwendet wird. Das heißt, es ist einfach so ein Moment. Es ist wichtig, es zu verstehen. Und es ist wichtig zu kontrollieren, dass dies angezeigt wird.
Datenspeicherung
Unser nächster Punkt betrifft die Datenspeicherung. Was tun mit ihnen und was tun im Allgemeinen mit der Persistenz in Kubernetes?
Ich denke noch einmal, innerhalb unseres , es gab ein Thema über die Datenbank in Kubernetes. Und es scheint mir, dass ich sogar ungefähr weiß, was Ihre Kollegen Ihnen gesagt haben, als sie gefragt wurden: „Ist es möglich, eine Datenbank in Kubernetes zu betreiben?“ Aus irgendeinem Grund hätten Ihre Kollegen Ihnen sagen sollen, dass es unmöglich ist, wenn Sie die Frage stellen, ob es möglich ist, eine Datenbank in Kubernetes auszuführen.
Die Logik hier ist einfach. Nur für den Fall, ich erkläre es noch einmal: Wenn Sie ein wirklich cooler Typ sind, der ein ziemlich fehlertolerantes System verteilter Netzwerkspeicher aufbauen kann, verstehen Sie, wie man eine Datenbank in diesen Fall einfügt und wie Cloud-nativ in Containern funktionieren sollte in einer Datenbank im Allgemeinen. Höchstwahrscheinlich haben Sie keine Frage, wie man es ausführt. Wenn Sie eine solche Frage haben und sicherstellen möchten, dass sich alles entfaltet und in der Produktion einwandfrei bleibt und niemals zusammenbricht, dann passiert das nicht. Mit dieser Vorgehensweise schießt man sich garantiert selbst ins Bein. Also besser nicht.
Was sollen wir mit den Daten machen, die unsere Anwendung speichern möchte, einigen Bildern, die Benutzer hochladen, einigen Dingen, die unsere Anwendung während ihres Betriebs generiert, zum Beispiel beim Start? Was tun mit ihnen in Kubernetes?
Im Allgemeinen, im Idealfall, ja, natürlich ist Kubernetes sehr gut konzipiert und ursprünglich ursprünglich für zustandslose Anwendungen konzipiert. Das heißt, für Anwendungen, die überhaupt keine Informationen speichern. Das ist ideal.
Aber natürlich gibt es nicht immer die ideale Option. Na und? Der erste und einfachste Punkt besteht darin, eine Art S3 zu nehmen, aber nicht ein selbstgebautes, bei dem auch unklar ist, wie es funktioniert, sondern von irgendeinem Anbieter. Ein guter, normaler Anbieter – und bringen Sie Ihrer Anwendung die Verwendung von S3 bei. Das heißt, wenn Ihr Benutzer eine Datei hochladen möchte, sagen Sie „Hier, bitte laden Sie sie in S3 hoch.“ Wenn er es erhalten möchte, sagen Sie: „Hier ist ein Link zu S3 zurück und nehmen Sie ihn von hier.“ Das ist ideal.
Wenn diese ideale Option plötzlich aus irgendeinem Grund nicht mehr passt, haben Sie eine Anwendung, die Sie nicht geschrieben oder entwickelt haben, oder es handelt sich um eine Art schreckliches Erbe, sie kann das S3-Protokoll nicht verwenden, sondern muss mit lokalen Verzeichnissen in arbeiten lokale Ordner. Nehmen Sie etwas mehr oder weniger Einfaches: Stellen Sie Kubernetes bereit. Das heißt, es scheint mir eine schlechte Idee zu sein, Ceph sofort für einige minimale Aufgaben einzuschränken. Denn Ceph ist natürlich gut und modisch. Aber wenn Sie nicht wirklich verstehen, was Sie tun, können Sie, sobald Sie etwas auf Ceph angelegt haben, es sehr leicht und einfach nie wieder herausbekommen. Denn wie Sie wissen, speichert Ceph Daten in seinem Cluster in binärer Form und nicht in Form einfacher Dateien. Wenn also der Ceph-Cluster plötzlich zusammenbricht, besteht eine vollständige und hohe Wahrscheinlichkeit, dass Sie Ihre Daten nie wieder von dort erhalten.
Wir werden einen Kurs über Ceph veranstalten, das können Sie .
Daher ist es besser, etwas Einfaches wie einen NFS-Server zu erstellen. Kubernetes kann damit arbeiten, Sie können ein Verzeichnis unter einem NFS-Server mounten – Ihre Anwendung ist genau wie ein lokales Verzeichnis. Gleichzeitig müssen Sie natürlich verstehen, dass Sie wiederum etwas mit Ihrem NFS tun müssen, Sie müssen verstehen, dass es manchmal unzugänglich werden kann, und überlegen, was Sie in diesem Fall tun werden. Vielleicht sollte es irgendwo auf einem separaten Computer gesichert werden.
Der nächste Punkt, über den ich gesprochen habe, ist, was zu tun ist, wenn Ihre Anwendung während des Betriebs einige Dateien generiert. Beim Start wird beispielsweise eine statische Datei generiert, die auf Informationen basiert, die die Anwendung erst zum Zeitpunkt des Starts erhält. Was für ein Moment. Wenn nicht viele solcher Daten vorhanden sind, müssen Sie sich überhaupt nicht darum kümmern. Installieren Sie diese Anwendung einfach selbst und arbeiten Sie. Die einzige Frage hier ist, was, schauen Sie. Sehr oft wissen alle möglichen Legacy-Systeme wie WordPress usw., insbesondere mit modifizierten cleveren Plugins, clevere PHP-Entwickler oft, wie man es so macht, dass sie eine Art Datei für sich selbst generieren. Dementsprechend generiert einer eine Datei, der zweite eine zweite Datei. Sie sind anders. Der Ausgleich geschieht im Kubernetes-Cluster der Kunden ganz zufällig. Dementsprechend stellt sich heraus, dass sie beispielsweise nicht wissen, wie sie zusammenarbeiten sollen. Einer gibt eine Information, der andere gibt dem Benutzer eine andere Information. Das sollten Sie vermeiden. Das heißt, in Kubernetes funktioniert garantiert alles, was Sie starten, in mehreren Instanzen. Denn Kubernetes ist eine bewegende Sache. Dementsprechend kann er alles bewegen, wann immer er will, ohne irgendjemanden zu fragen. Deshalb müssen Sie damit rechnen. Alles, was in einer Instanz gestartet wird, wird früher oder später scheitern. Je mehr Reservierungen Sie haben, desto besser. Aber noch einmal, ich sage: Wenn Sie ein paar solcher Akten haben, dann können Sie sie direkt unter sich ablegen, sie wiegen ein kleines Gewicht. Wenn es etwas mehr davon gibt, sollten Sie sie wahrscheinlich nicht in den Behälter schieben.
Ich würde darauf hinweisen, dass es in Kubernetes etwas Wunderbares gibt: Sie können Volumen verwenden. Insbesondere gibt es ein Volume vom Typ leeres Verzeichnis. Das heißt, Kubernetes erstellt lediglich automatisch ein Verzeichnis in seinen Dienstverzeichnissen auf dem Server, auf dem Sie gestartet haben. Und er wird es dir geben, damit du es nutzen kannst. Es gibt nur einen wichtigen Punkt. Das heißt, Ihre Daten werden nicht im Container gespeichert, sondern auf dem Host, auf dem Sie ausgeführt werden. Darüber hinaus kann Kubernetes solche leeren Verzeichnisse bei normaler Konfiguration kontrollieren und ist in der Lage, ihre maximale Größe zu kontrollieren und nicht zuzulassen, dass sie überschritten wird. Der einzige Punkt ist, dass das, was Sie in das leere Verzeichnis geschrieben haben, beim Neustart des Pods nicht verloren geht. Das heißt, wenn Ihr Pod versehentlich herunterfällt und wieder hochsteigt, werden die Informationen im leeren Verzeichnis nirgendwo hingehen. Er kann es bei einem Neuanfang wieder nutzen – und das ist gut so. Wenn Ihr Pod irgendwohin geht, wird er natürlich ohne Daten verschwinden. Das heißt, sobald der Pod von dem Knoten, auf dem er mit leerem Verzeichnis gestartet wurde, verschwindet, wird auch das leere Verzeichnis gelöscht.
Was ist sonst noch gut an leerem Verzeichnis? Es kann beispielsweise als Cache verwendet werden. Stellen wir uns vor, dass unsere Anwendung spontan etwas generiert, es an Benutzer weitergibt und dies über einen längeren Zeitraum tut. Daher generiert die Anwendung es beispielsweise, gibt es an Benutzer weiter und speichert es gleichzeitig irgendwo, sodass der Benutzer das nächste Mal, wenn er das Gleiche verlangt, schneller ist, um es sofort generiert bereitzustellen. Kubernetes kann aufgefordert werden, ein leeres Verzeichnis im Speicher zu erstellen. Und so können Ihre Caches im Allgemeinen blitzschnell arbeiten – was die Geschwindigkeit des Festplattenzugriffs betrifft. Das heißt, Sie haben ein leeres Verzeichnis im Speicher, im Betriebssystem wird es im Speicher gespeichert, aber für Sie, für den Benutzer im Pod, sieht es nur wie ein lokales Verzeichnis aus. Sie benötigen die App nicht, um gezielt Magie zu lehren. Sie nehmen Ihre Datei einfach direkt und legen sie in einem Verzeichnis ab, tatsächlich jedoch im Speicher des Betriebssystems. Dies ist auch im Hinblick auf Kubernetes eine sehr praktische Funktion.
Welche Probleme hat Minio? Das Hauptproblem bei Minio besteht darin, dass dieses Ding irgendwo laufen muss, damit es funktioniert, und es muss eine Art Dateisystem, also Speicher, vorhanden sein. Und hier stoßen wir auf die gleichen Probleme wie Ceph. Das heißt, Minio muss seine Dateien irgendwo speichern. Es handelt sich lediglich um eine HTTP-Schnittstelle zu Ihren Dateien. Zudem ist die Funktionalität deutlich schlechter als beim Amazon S3. Bisher war es nicht möglich, den Benutzer ordnungsgemäß zu autorisieren. Nun kann es meines Wissens zwar bereits Buckets mit unterschiedlichen Berechtigungen erstellen, aber auch hier scheint mir zumindest das Hauptproblem sozusagen das zugrunde liegende Speichersystem zu sein.
Wie wirkt sich ein leeres Verzeichnis im Speicher auf die Grenzwerte aus? Beeinflusst die Grenzwerte in keiner Weise. Es liegt im Speicher des Hosts und nicht im Speicher Ihres Containers. Das heißt, Ihr Container sieht das leere Verzeichnis im Speicher nicht als Teil seines belegten Speichers. Der Gastgeber sieht dies. Dementsprechend wäre es aus der Sicht von Kubernetes gut zu verstehen, dass Sie einen Teil Ihres Speichers dem leeren Verzeichnis widmen, wenn Sie damit beginnen. Und verstehen Sie dementsprechend, dass der Speicher nicht nur aufgrund von Anwendungen knapp werden kann, sondern auch, weil jemand in diese leeren Verzeichnisse schreibt.
Cloudnativität
Und das letzte Unterthema ist, was Cloudnative ist. Warum wird es benötigt? Cloudnativität und so weiter.
Das sind jene Anwendungen, die in der Lage und geschrieben sind, in einer modernen Cloud-Infrastruktur zu funktionieren. Aber tatsächlich hat Cloudnative noch einen weiteren solchen Aspekt. Dass es sich nicht nur um eine Anwendung handelt, die alle Anforderungen einer modernen Cloud-Infrastruktur berücksichtigt, sondern auch weiß, wie man mit dieser modernen Cloud-Infrastruktur arbeitet, nutzen Sie die Vor- und Nachteile der Tatsache, dass sie in diesen Clouds funktioniert. Übertreiben Sie es nicht und arbeiten Sie in der Cloud, sondern nutzen Sie die Vorteile der Arbeit in der Cloud.

Nehmen wir einfach Kubernetes als Beispiel. Ihre Anwendung wird in Kubernetes ausgeführt. Ihre Anwendung kann jederzeit bzw. die Administratoren Ihrer Anwendung können jederzeit ein Dienstkonto erstellen. Das heißt, ein Konto zur Autorisierung in Kubernetes selbst auf seinem Server. Fügen Sie dort einige Rechte hinzu, die wir benötigen. Und Sie können von Ihrer Anwendung aus auf Kubernetes zugreifen. Was können Sie auf diese Weise tun? Erhalten Sie beispielsweise von der Anwendung Daten darüber, wo sich Ihre anderen Anwendungen und andere ähnliche Instanzen befinden, und gruppieren Sie sie bei Bedarf irgendwie auf Kubernetes.
Auch hier hatten wir vor Kurzem buchstäblich einen Fall. Wir haben einen Controller, der die Warteschlange überwacht. Und wenn in dieser Warteschlange neue Aufgaben auftauchen, wird sie an Kubernetes weitergeleitet – und innerhalb von Kubernetes wird ein neuer Pod erstellt. Gibt diesem Pod eine neue Aufgabe und im Rahmen dieses Pods führt der Pod die Aufgabe aus, sendet eine Antwort an den Controller selbst, und der Controller macht dann etwas mit diesen Informationen. Es fügt zum Beispiel eine Datenbank zusammen. Das ist wiederum ein Pluspunkt der Tatsache, dass unsere Anwendung in Kubernetes läuft. Wir können die integrierte Kubernetes-Funktionalität selbst verwenden, um die Funktionalität unserer Anwendung irgendwie zu erweitern und komfortabler zu gestalten. Das heißt, verbergen Sie keine Magie darüber, wie eine Anwendung oder ein Worker gestartet wird. In Kubernetes senden Sie einfach eine Anfrage in der App, wenn die Anwendung in Python geschrieben ist.
Das Gleiche gilt, wenn wir über Kubernetes hinausgehen. Irgendwo läuft unser Kubernetes – am besten in einer Art Cloud. Auch hier können wir die Fähigkeiten der Cloud selbst, in der wir arbeiten, nutzen und sollten dies meiner Meinung nach sogar tun. Von den elementaren Dingen, die uns die Cloud bietet. Balancing, das heißt, wir können Cloud-Balancer erstellen und diese nutzen. Das ist ein direkter Vorteil dessen, was wir nutzen können. Denn erstens entzieht uns das Cloud-Balancing einfach dummerweise die Verantwortung dafür, wie es funktioniert und wie es konfiguriert ist. Außerdem ist es sehr praktisch, da normales Kubernetes in Clouds integriert werden kann.
Das Gleiche gilt für die Skalierung. Reguläres Kubernetes kann mit Cloud-Anbietern integriert werden. Weiß, wie man versteht, dass, wenn dem Cluster die Knoten ausgehen, das heißt, der Knotenplatz aufgebraucht ist, Sie hinzufügen müssen – Kubernetes selbst fügt Ihrem Cluster neue Knoten hinzu und beginnt mit dem Starten von Pods darauf. Das heißt, wenn Ihre Ladung kommt, beginnt die Anzahl der Herde zuzunehmen. Wenn die Knoten im Cluster für diese Pods erschöpft sind, startet Kubernetes neue Knoten und dementsprechend kann die Anzahl der Pods noch steigen. Und es ist sehr praktisch. Dies ist eine direkte Möglichkeit, den Cluster im laufenden Betrieb zu skalieren. Nicht sehr schnell, in dem Sinne, dass es keine Sekunde dauert, sondern eher eine Minute, um neue Knoten hinzuzufügen.
Aber meiner Erfahrung nach ist es das Coolste, was ich je gesehen habe. Wenn der Cloudnative-Cluster basierend auf der Tageszeit skaliert wird. Es handelte sich um einen Backend-Dienst, der von Mitarbeitern im Backoffice genutzt wurde. Das heißt, sie kommen um 9 Uhr morgens zur Arbeit, beginnen mit der Anmeldung im System, und dementsprechend wächst der Cloudnative-Cluster, in dem alles läuft, und startet neue Pods, damit jeder, der zur Arbeit kommt, mit der Anwendung arbeiten kann. Wenn sie um 8 oder 6 Uhr die Arbeit verlassen, merken die Kubernetes-Cluster, dass niemand mehr die Anwendung nutzt und beginnen zu schrumpfen. Einsparungen von bis zu 30 Prozent sind garantiert. Damals funktionierte es bei Amazon; damals gab es in Russland niemanden, der das so gut konnte.
Ich sage es Ihnen ganz klar: Die Einsparungen betragen 30 Prozent, allein weil wir Kubernetes verwenden und die Möglichkeiten der Cloud nutzen. Jetzt ist dies in Russland möglich. Ich werde natürlich niemandem Werbung machen, aber sagen wir einfach, es gibt Anbieter, die das können, also direkt per Knopfdruck bereitstellen.
Es gibt noch einen letzten Punkt, auf den ich Sie noch aufmerksam machen möchte. Damit Ihre Anwendung, Ihre Infrastruktur Cloudnativ ist, ist es sinnvoll, endlich mit der Adaption des Ansatzes „Infrastructure as a Code“ zu beginnen. Das heißt, dass Ihre Anwendung bzw. Ihre Infrastruktur genauso benötigt wird wie die Code Beschreiben Sie Ihre Anwendung, Ihre Geschäftslogik in Form von Code. Und damit als Code arbeiten, das heißt, testen, ausrollen, in Git speichern, CICD darauf anwenden.
Und genau das ermöglicht es Ihnen erstens, immer die Kontrolle über Ihre Infrastruktur zu haben und immer zu verstehen, in welchem Zustand sie sich befindet. Zweitens vermeiden Sie manuelle Vorgänge, die Fehler verursachen. Drittens vermeiden Sie einfach das, was man Fluktuation nennt, wenn Sie ständig die gleichen manuellen Aufgaben erledigen müssen. Viertens ermöglicht es Ihnen im Falle eines Ausfalls eine viel schnellere Wiederherstellung. In Russland gibt es jedes Mal, wenn ich darüber spreche, eine große Anzahl von Menschen, die sagen: „Ja, es ist klar, aber Sie haben Ansätze, kurz gesagt, es besteht keine Notwendigkeit, etwas zu reparieren.“ Aber es ist wahr. Wenn in Ihrer Infrastruktur etwas kaputt ist, dann ist es aus der Sicht des Cloudnative-Ansatzes und aus der Sicht von Infrastructure as a Code einfacher, als es zu reparieren, zum Server zu gehen, herauszufinden, was kaputt ist, und es zu reparieren um den Server zu löschen und neu zu erstellen. Und ich werde das alles wiederherstellen lassen.
Alle diese Themen werden ausführlicher besprochen unter . Wenn Sie dem Link folgen, können Sie sich mit dem Programm und den Bedingungen vertraut machen. Das Praktische daran ist, dass Sie Kubernetes beherrschen können, indem Sie 1–2 Stunden am Tag von zu Hause aus lernen oder arbeiten.
Source: habr.com
