Die Geschichte der Bereitstellung, die alles betraf

Die Geschichte der Bereitstellung, die alles betraf
Feinde der Realität von 12f-2

Ende April, während die Weißen Wanderer Winterfell belagerten, hatten wir etwas Interessanteres – wir führten ein etwas ungewöhnliches Rollout durch. Im Grunde genommen bringen wir ständig neue Funktionen in die Produktion (wie alle anderen auch). Aber dieses Rollout war anders als die anderen. Der Umfang war so groß, dass jede potenzielle Fehlentscheidung, die wir treffen könnten, alle unsere Dienste und Nutzer betroffen hätte. Letztendlich haben wir alles nach Plan umgesetzt, innerhalb des angekündigten Zeitrahmens ohne Auswirkungen auf den Betrieb. Der Artikel handelt davon, wie wir das erreicht haben und wie Interessierte dies zu Hause nachmachen können.

Ich werde jetzt nicht die von uns getroffenen architektonischen und technischen Entscheidungen beschreiben oder erklären, wie alles funktioniert. Vielmehr handelt es sich um Anmerkungen am Rande, wie eines der komplexesten Rollouts, die ich je gesehen habe und an dem ich direkt beteiligt war, ablief. Ich beanspruche nicht die Vollständigkeit oder technischen Details; diese werden möglicherweise in einem anderen Artikel erscheinen.

Vorgeschichte + was für eine Funktionalität das ist

Wir bauen eine Cloud-Plattform Mail.ru Cloud Lösungen (MCS), wo ich als technischer Direktor arbeite. Nun ist es an der Zeit, unserer Plattform IAM (Identity and Access Management) hinzuzufügen, die ein zentrales Management aller Benutzerkonten, Nutzer, Passwörter, Rollen, Dienste und mehr ermöglicht. Die Notwendigkeit dafür im Cloud-Umfeld liegt auf der Hand: Hier wird alle Benutzerinformation gespeichert.

Solche Dinge werden normalerweise in der Anfangsphase jeder Projekte entwickelt. Aber bei MCS hat sich das historisch etwas anders entwickelt. MCS wurde in zwei Teilen aufgebaut:

  • OpenStack mit einem eigenen Autorisierungsmodul namens Keystone,
  • Hotbox (S3-Speicher) basierend auf dem Projekt Cloud Mail.ru,

um die herum dann neue Dienste entstanden.

Im Grunde genommen waren das zwei verschiedene Arten der Autorisierung. Außerdem haben wir einige separate Entwicklungen von Mail.ru verwendet, wie etwa das allgemeine Passwortspeicher von Mail.ru, sowie einen selbst entwickelten OpenID-Connector, der die SSO (Single Sign-On) im Horizon-Dashboard der virtuellen Maschinen (natives UI von OpenStack) ermöglichte.

Die Erstellung von IAM bedeutete für uns, alles in ein einheitliches System zu integrieren, das vollständig uns gehörte. Dabei wollten wir keinen Funktionsverlust riskieren und gleichzeitig eine Grundlage für die Zukunft schaffen, die es uns erlaubt, es transparent weiterzuentwickeln, ohne umfangreiche Refaktorisierungen vorzunehmen und die Funktionalität zu skalieren. Zu Beginn erhielten die Benutzer außerdem ein Rollenmodell für den Zugriff auf die Dienste (zentraler RBAC, role-based access control) sowie einige weitere kleine Funktionen.

Die Aufgabe stellte sich als alles andere als trivial heraus: Python und Perl, mehrere Backends, unabhängig entwickelte Dienste, mehrere Entwicklungsteams und Administratoren. Und vor allem – Tausende von aktiven Benutzern auf einem Produktionssystem. All dies musste geschrieben und, was am wichtigsten ist, ohne Verluste implementiert werden.

Was wir bereitgestellt haben

Wenn man es sehr grob betrachtet, haben wir in etwa 4 Monaten Folgendes vorbereitet:

  • Wir haben einige neue Daemons entwickelt, die Funktionen aggregieren, die zuvor in verschiedenen Teilen der Infrastruktur arbeiteten. Den anderen Diensten haben wir ein neues Backend in Form dieser Daemons zugewiesen.
  • Wir haben unser zentrales Passwort- und Schlüssel-Repository geschrieben, das für all unsere Dienste zugänglich ist und das wir nach Belieben modifizieren können.
  • Wir haben von Grund auf 4 neue Backends für Keystone entwickelt (Benutzer, Projekte, Rollen, Rollenzuweisungen), die im Grunde seine Datenbank ersetzt haben und nun als zentrales Repository für unsere Benutzerpasswörter dienen.
  • Wir haben all unsere OpenStack-Dienste so konfiguriert, dass sie ihre Richtlinien von einem externen Dienst abrufen, anstatt diese lokal von jedem Server zu lesen (ja, genau, OpenStack funktioniert standardmäßig so!).

Eine so umfassende Umgestaltung erfordert große, komplexe und vor allem synchronisierte Änderungen in mehreren Systemen, die von verschiedenen Entwicklungsteams erstellt wurden. Nach dem Rollout muss das gesamte System reibungslos funktionieren.

Wie man solche Änderungen einführt, ohne zu scheitern? Zunächst haben wir beschlossen, einen kleinen Blick in die Zukunft zu werfen.

Rollout-Strategie

  • Man könnte den Rollout in mehreren Phasen durchführen, aber das würde die Entwicklungszeit um das Dreifache verlängern. Außerdem hätten wir für einige Zeit eine vollständige Desynchronisierung der Daten in den Datenbanken. Wir müssten unsere eigenen Synchronisierungstools schreiben und eine lange Zeit mit mehreren Datenspeichern leben. Das birgt eine Vielzahl von Risiken.
  • Alles, was wir für die Benutzer transparent vorbereiten konnten, wurde im Voraus erledigt. Dafür haben wir zwei Monate benötigt.
  • Wir haben uns für einige Stunden Downtime entschieden – nur für die Operationen der Nutzer zur Erstellung und Änderung von Ressourcen.
  • Für den Betrieb aller bereits erstellten Ressourcen war eine Downtime nicht akzeptabel. Wir haben eingeplant, dass die Ressourcen beim Rollout ohne Downtime und Auswirkungen für die Kunden funktionieren müssen.
  • Um die Auswirkungen auf unsere Kunden zu minimieren, falls etwas schiefgeht, haben wir uns entschieden, am Sonntagabend zu rollen. Nachts beschäftigen sich weniger Kunden mit der Verwaltung virtueller Maschinen.
  • Wir haben alle unsere Kunden darüber informiert, dass während des vorgesehenen Rollout-Zeitraums die Verwaltung der Services nicht verfügbar sein wird.

Ein Einschub: Was ist ein Rollout?

<осторожно, философия>

Jeder ITler kann leicht beantworten, was ein Rollout ist. Man installiert CI/CD und alles wird automatisch in die Produktion geliefert. 🙂

Das stimmt auf jeden Fall. Allerdings besteht die Herausforderung darin, dass bei modernen Automatisierungstools das Verständnis für die Bereitstellung oft verloren geht. Man vergisst fast die Bedeutung der Erfindung des Rades, wenn man sich modernen Verkehrsmitteln gegenübersieht. Alles ist so stark automatisiert, dass die Bereitstellung häufig ohne ein umfassendes Verständnis des gesamten Ablaufs erfolgt.

Das Gesamtbild ist folgendes: Die Bereitstellung besteht aus vier wesentlichen Aspekten:

  1. Die Bereitstellung von Code, einschließlich der Datenänderungen. Zum Beispiel deren Migration.
  2. Die Rückgängigmachung des Codes – die Möglichkeit, zurückzukehren, falls etwas schiefgeht. Zum Beispiel durch die Erstellung von Backups.
  3. Die Dauer jeder Bereitstellungs-/Rückgängigmachung. Es ist wichtig, das Timing jeder der ersten beiden Punkte zu verstehen.
  4. Der betroffene Funktionsumfang. Es ist unerlässlich, sowohl die potenziell positiven als auch die möglichen negativen Effekte zu beurteilen.

Alle diese Aspekte sind für eine erfolgreiche Bereitstellung zu berücksichtigen. Normalerweise werden nur der erste und im besten Fall der zweite Punkt bewertet, und dann gilt die Bereitstellung als erfolgreich. Doch der dritte und vierte Punkt sind sogar noch wichtiger. Welcher Benutzer würde sich freuen, wenn die Bereitstellung 3 Stunden anstatt einer Minute dauert? Oder wenn während der Bereitstellung etwas anderes betroffen ist? Oder wenn die Ausfallzeit eines Dienstes zu unvorhersehbaren Folgen führt?

Akt 1..n, Vorbereitung auf das Release

Zuerst dachte ich daran, unsere Treffen kurz zu beschreiben: das gesamte Team, seine Teile, viele Diskussionen in den Kaffee-Punkten, Streitigkeiten, Tests, Brainstormings. Dann dachte ich, das wäre überflüssig. Vier Monate Entwicklung bestehen immer aus solchen Momenten, besonders wenn man nicht das entwickelt, was kontinuierlich ausgeliefert werden kann, sondern eine große Funktion für ein aktives System. Diese betrifft alle Dienste, aber für die Benutzer sollte sich nichts ändern, außer "einem Knopf im Web-Interface".

Unsere Erkenntnisse darüber, wie man Rollouts effektiv gestaltet, haben sich bei jedem neuen Treffen erheblich verändert. Zum Beispiel planten wir ein Update unserer gesamten Abrechnungsdatenbank. Doch als wir die Zeit kalkulierten, stellte sich heraus, dass es nicht möglich war, dies in einem vernünftigen Rollout-Zeitraum umzusetzen. Wir benötigten fast eine zusätzliche Woche, um die Abrechnungsdatenbank zu sharden und zu archivieren. Und als die erwartete Rollout-Geschwindigkeit danach immer noch nicht zufriedenstellend war, bestellten wir zusätzliche leistungsstärkere Hardware, um die gesamte Datenbank dorthin zu migrieren. Es war nicht so, dass wir das nicht früher hätten tun wollen, aber die aktuellen Rollout-Anforderungen ließen uns keine andere Wahl.

Als einer von uns Bedenken äußerte, dass der Rollout die Verfügbarkeit unserer virtuellen Maschinen beeinträchtigen könnte, nahmen wir uns eine Woche Zeit für Tests, Experimente und die Analyse des Codes. So erhielten wir ein klares Verständnis, dass dies in unserer Produktionsumgebung nicht der Fall sein würde, und selbst die skeptischsten Personen stimmten dem zu.

In der Zwischenzeit haben die Kollegen aus dem technischen Support unabhängige Experimente durchgeführt, um den Kunden Anleitungen zu den neuen Verbindungsmöglichkeiten zu schreiben, die sich nach dem Deployment ändern sollten. Sie haben die Benutzererfahrung optimiert, Anleitungen erstellt und persönliche Beratungen angeboten.

Wir haben alle möglichen Operationen im Zusammenhang mit dem Deployment automatisiert. Jede Operation wurde skriptiert, selbst die einfachste, und wir haben ständig Tests durchgeführt. Wir haben darüber diskutiert, wie der Dienst am besten deaktiviert werden kann – durch das Stoppen des Dienstes oder durch das Sperren des Zugangs über die Firewall. Ein Checkliste für jedes Schritt des Deployments wurde erstellt und kontinuierlich aktualisiert. Zudem haben wir ein Gantt-Diagramm für alle Deployment-Arbeiten erstellt und stetig aktualisiert, mit Zeitvorgaben.

Und nun…

Der finale Akt, vor dem Deployment

… ist die Zeit für das Deployment gekommen.

Wie man so schön sagt, ein Kunstwerk kann man nicht vollenden, man kann nur aufhören, daran zu arbeiten. Man muss den Willen aufbringen, zu verstehen, dass man nicht alles findet, aber zu glauben, dass man alle sinnvollen Annahmen getroffen, alle möglichen Fälle bedacht, alle kritischen Bugs behoben und alle Beteiligten ihr Bestes gegeben haben. Je mehr Code man ausrollt, desto schwieriger wird es, sich selbst davon zu überzeugen (außerdem versteht jeder, dass es unmöglich ist, alles vorherzusehen).

Wir haben entschieden, dass wir bereit sind, live zu gehen, als wir uns dessen sicher waren, dass wir alles Mögliche getan haben, um alle Risiken für unsere Nutzer in Bezug auf unerwartete Effekte und Ausfallzeiten zu minimieren. Das heißt – dass alles schiefgehen kann, außer:

  1. Dem Einfluss (der für uns heiligen, wertvollsten) Nutzerinfrastruktur.
  2. Funktionalitäten: Die Nutzung unseres Dienstes nach dem Rollout muss dieselbe sein wie davor.

Rollout

Die Geschichte der Bereitstellung, die alles betraf
Zwei rollen, acht stören nicht

Wir haben für alle Anfragen von Nutzern während 7 Stunden eine Ausfallzeit eingeplant. Für diese Zeit haben wir sowohl einen Rollout- als auch einen Rollback-Plan.

  • Der Rollout selbst dauert etwa 3 Stunden.
  • 2 Stunden sind für das Testing eingeplant.
  • 2 Stunden – Puffer für mögliche Rückänderungen.

Ein Gantt-Diagramm wurde für jede Aktivität erstellt, das zeigt, wie viel Zeit sie in Anspruch nimmt, welche Aktivitäten sequenziell ablaufen und welche parallel durchgeführt werden.

Die Geschichte der Bereitstellung, die alles betraf
Ausschnitt aus dem Gantt-Diagramm der Version, eine der frühen Versionen (ohne parallele Ausführung). Ein wertvolles Synchronisationswerkzeug.

Für alle Beteiligten wurde ihre Rolle im Rollout definiert, welche Aufgaben sie übernehmen und wofür sie verantwortlich sind. Wir streben an, jeden Schritt zu automatisieren, Rollouts durchzuführen, Feedback zu sammeln und erneut zu starten.

Chronik der Ereignisse

Am Sonntag, den 29. April, um 22 Uhr kamen insgesamt 15 Personen zur Arbeit. Neben den Schlüsselmitgliedern kamen einige einfach zur Unterstützung des Teams, wofür wir ihnen besonders danken.

Es ist erwähnenswert, dass unser leitender Tester im Urlaub ist. Ein Rollout ohne Tests ist nicht möglich, wir prüfen Alternativen. Eine Kollegin erklärt sich bereit, aus dem Urlaub zu testen, wofür wir ihr im Namen des gesamten Teams unermessliche Dankbarkeit aussprechen.

00:00. Halt
Wir stoppen die Benutzeranfragen und bringen ein Schild an, dass technische Arbeiten durchgeführt werden. Das Monitoring schlägt Alarm, aber alles läuft nach Plan. Wir überprüfen, dass nichts abgestürzt ist, außer dem, was sollte. Und wir beginnen mit der Migration.

Alle haben einen ausgedruckten Rollout-Plan mit den einzelnen Punkten, jeder weiß, wer was zu welchem Zeitpunkt macht. Nach jeder Aktion überprüfen wir die Zeitplanung, um sicherzustellen, dass wir im Zeitrahmen bleiben und alles nach Plan verläuft. Diejenigen, die zu diesem Zeitpunkt nicht direkt am Rollout beteiligt sind, bereiten sich vor, indem sie ein Online-Spiel (Xonotic, so ähnlich wie 3D-Shooter) starten, um die Kollegen nicht zu stören. 🙂

02:00. Rollout abgeschlossen
Eine angenehme Überraschung — wir beenden den Rollout eine Stunde früher dank der Optimierung unserer Datenbanken und Migration-Skripte. Ein allgemeiner Ruf „Rollout abgeschlossen!“ Alle neuen Funktionen sind live, aber im Interface sehen es vorerst nur wir. Alle schalten in den Testmodus um, bilden Gruppen und beginnen zu überprüfen, was letztendlich entstanden ist.

Das Ergebnis ist nicht optimal, das merken wir etwa nach 10 Minuten, als in den Projekten der Teammitglieder nichts verbunden ist und nicht funktioniert. Schneller Sync, wir kommunizieren unsere Probleme, setzen Prioritäten, bilden Teams und gehen in die Fehlersuche.

02:30. Zwei große Probleme gegen vier Augen
Wir entdecken zwei große Probleme. Uns ist aufgefallen, dass die Auftraggeber einige verbundene Services nicht sehen und es zu Problemen mit den Partnerkonten kommt. Beide hängen mit der Unvollkommenheit der Migrationsskripte für einige Randfälle zusammen. Das muss jetzt behoben werden.

Wir schreiben Anfragen, die das beheben, mindestens mit vier Augen. Wir testen im Staging, um sicherzustellen, dass sie funktionieren und nichts kaputt machen. Danach kann es weitergehen. Parallel dazu läuft unser normales Integrationstestverfahren, das noch einige weitere Probleme entdeckt. Alle sind klein, müssen aber ebenfalls behoben werden.

03:00. -2 Probleme +2 Probleme
Die beiden vorherigen großen Probleme sind behoben, fast alle kleinen ebenfalls. Alle, die nicht mit Fixes beschäftigt sind, arbeiten aktiv in ihren Konten und berichten, was sie finden. Wir priorisieren, verteilen es auf die Teams und lassen nicht kritische Sachen bis zum Morgen.

Wir starten die Tests erneut, und sie entdecken zwei neue große Probleme. Nicht alle Service-Richtlinien wurden richtig übertragen, sodass einige Benutzeranfragen nicht autorisiert werden. Zudem gibt es ein neues Problem mit den Partnerkonten. Wir schauen uns das an.

03:20. Notfall-Sync
Ein neues Problem wurde behoben. Für das zweite Problem organisieren wir einen Notfall-Sync. Wir verstehen, was passiert: Der vorherige Fix hat ein Problem gelöst, aber ein neues geschaffen. Wir machen eine Pause, um herauszufinden, wie wir es richtig und ohne negative Folgen angehen.

03:30. Sechs Augen
Wir sind uns bewusst, wie der endgültige Zustand der Datenbank aussehen sollte, damit alles für alle Partner gut funktioniert. Wir schreiben eine Anfrage an 6 Augen, führen es in der Pre-Production durch, testen es und bringen es in die Produktion.

04:00. Alles funktioniert
Alle Tests sind bestanden, kritische Probleme sind nicht sichtbar. Gelegentlich funktioniert bei jemandem im Team etwas nicht, und wir reagieren sofort. Meistens sind die Bedenken unbegründet. Aber manchmal hat etwas nicht funktioniert, eine bestimmte Seite arbeitet nicht. Wir sitzen zusammen, fixen, fixen, fixen. Ein separates Team startet das letzte große Feature - das Billing.

04:30. Der Wendepunkt
Der Zeitpunkt des Unumkehrbaren nähert sich, das heißt, der Moment, in dem wir, falls wir zurückrollen müssen, die vorgegebene Ausfallzeit nicht einhalten können. Es gibt Probleme mit der Abrechnung, die zwar alles wissen und protokollieren, aber hartnäckig kein Geld von den Kunden abbuchen wollen. Einige Bugs auf bestimmten Seiten, Aktionen und Status sind vorhanden. Die Hauptfunktionen laufen, alle Tests sind erfolgreich. Wir entscheiden, dass das Rollout erfolgreich war und keine Rückrolle stattfinden wird.

06:00. Wir öffnen die UI für alle.
Bugs wurden behoben. Einige, die die Nutzer nicht betreffen, werden auf später verschoben. Wir öffnen die Benutzeroberfläche für alle. Wir arbeiten weiter am Abrechnungssystem und warten auf das Feedback der Nutzer sowie die Ergebnisse des Monitorings.

07:00. Probleme mit der API-Auslastung.
Es wird klar, dass wir die Last auf unserer API und das Testen dieser Last etwas falsch eingeplant haben, was das Problem nicht aufdecken konnte. Infolgedessen scheitern etwa 5 % der Anfragen. Wir mobilisieren uns und suchen nach der Ursache.

Das Billing macht weiterhin Probleme und funktioniert ebenfalls nicht. Wir verschieben es, um die Änderungen in Ruhe durchführen zu können. Das heißt, alle Ressourcen werden angesammelt, aber die Abbuchungen bei den Kunden erfolgen nicht. Natürlich ist das ein Problem, aber im Vergleich zu den allgemeinen Deployments scheint es nicht so entscheidend zu sein.

08:00. API Fix
Wir haben einen Fix für die Lastausgleichung ausgerollt, die Fehler sind verschwunden. Wir fangen an, nach Hause zu gehen.

10:00. Alles
Alles ist behoben. Im Monitoring und bei den Kunden ist Ruhe eingekehrt, das Team zieht sich allmählich zum Schlafen zurück. Das Billing bleibt, wir werden es morgen wiederherstellen.

Im Laufe des Tages gab es Rollouts, die die Logs, Benachrichtigungen, Rückgabecodes und Anpassungen für einige unserer Kunden behoben haben.

Also, der Rollout war erfolgreich! Es hätte natürlich besser sein können, aber wir haben Lehren daraus gezogen, was uns gefehlt hat, um Perfektion zu erreichen.

Gesamt

In den 2 Monaten aktiver Vorbereitung auf den Rollout wurden 43 Aufgaben erledigt, die von ein paar Stunden bis zu mehreren Tagen dauerten.

Während des Rollouts:

  • neue und geänderte Daemons – 5 Stück, die 2 Monolithen ersetzt haben;
  • Änderungen innerhalb der Datenbanken – alle 6 unserer Benutzerdatenbanken waren betroffen, Exporte aus drei alten Datenbanken in eine neue wurden durchgeführt;
  • komplett überarbeitete Frontend;
  • Die Menge des ausgegebenen Codes beträgt 33.000 Zeilen neuen Codes, ≈ 3.000 Zeilen Testcode, ≈ 5.000 Zeilen Migrationscode;
  • Alle Daten sind intakt, niemand der virtuellen Maschinen des Kunden wurde beeinträchtigt. 🙂

Gute Praktiken für ein erfolgreiches Rollout

Diese haben uns in dieser komplexen Situation geleitet. Grundsätzlich sind sie jedoch bei jedem Rollout nützlich. Je komplizierter das Rollout ist, desto wichtiger sind sie.

  1. Das erste, was wichtig ist — zu verstehen, wie das Rollout die Benutzer beeinflussen kann oder beeinflussen wird. Kommt es zu Ausfallzeiten? Wenn ja, wodurch? Wie wirkt sich das auf die Benutzer aus? Was sind die möglichen besten und schlechtesten Szenarien? Und die Risiken berücksichtigen.
  2. Alles planen. In jeder Phase muss man alle Aspekte des Rollouts verstehen:
    • Codeauslieferung;
    • Code-Rollback;
    • Zeit jeder Operation;
    • Betroffene Funktionalität.
  3. Szenarien durchspielen, bis alle Phasen des Rollouts und die Risiken in jeder Phase offensichtlich werden. Wenn Zweifel bestehen, ist es möglich, eine Pause einzulegen und den fraglichen Schritt separat zu untersuchen.
  4. Jeder Schritt kann und sollte verbessert werden, wenn es unseren Nutzern hilft, beispielsweise um die Ausfallzeiten zu reduzieren oder Risiken zu minimieren.
  5. Rollback-Tests sind weitaus wichtiger als das Testing des Code-Deployments. Es muss sichergestellt werden, dass das System nach einem Rollback in den ursprünglichen Zustand zurückkehrt und dies durch Tests bestätigt wird.
  6. Alles, was automatisiert werden kann, sollte automatisiert werden. Was nicht automatisiert werden kann, sollte im Voraus als Erinnerung festgehalten werden.
  7. Den Erfolgskriterium festlegen. Welche Funktionalitäten sollten zu welchem Zeitpunkt verfügbar sein? Wenn dies nicht gegeben ist, aktivieren Sie den Rollback-Plan.
  8. Und am wichtigsten sind die Menschen. Jeder sollte wissen, was er tut, warum und welche Auswirkungen sein Handeln während des Deployments hat.

In einem Satz zusammengefasst: Mit guter Planung und Vorbereitung kann man alles ohne negative Folgen für die Produktion ausrollen, selbst Dinge, die alle Ihre Dienste in der Produktion betreffen.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster