Infrastruktur als Code: Ein zweischneidiges Schwert
In einer sich ständig weiterentwickelnden Technologielandschaft ist der Umgang mit komplexen Umgebungen alles andere als ein Kinderspiel. Von größeren und teureren Betriebsteams bis hin zu einer strengeren Standardisierung von Hardware und Software wurden viele Strategien auf den Prüfstand gestellt. Automatisierung und aktuelle Schlagworte haben alle ihre Zeit im Rampenlicht gehabt.
Wir sind seit einiger Zeit dabei, das Paradigma "Infrastruktur als Code" (IaC) zu übernehmen. Dieser Ansatz lässt sich gut skalieren, erfordert weniger Ressourcen, lässt sich nahtlos mit anderen Tools und Prozessen wie Versionskontrolle und Änderungsverfolgung integrieren und ist ein effizienterer Weg, um die ständig wachsenden Anforderungen der heutigen digitalen Welt zu bewältigen.
Allerdings ist IaC, wie alles andere auch, nicht ohne Makel. Wir haben jahrzehntelange Erfahrung in der Verwaltung der Infrastruktur, aber der "Code"-Teil des IaC ist der Bereich, in dem Probleme auftreten. Wenn die Anzahl der Bugs, Patches, Exploits, Bug Bounties und anderer damit verbundener Aktivitäten ein Indiz dafür ist, dann ist klar, dass wir unsere Programmierfähigkeiten verbessern müssen.
Wenn verschiedene Softwarepakete anekdotisch verglichen werden, nicht weil sie leistungsfähig oder zuverlässig sind, sondern weil sie genauso fehlerhaft sind wie andere Pakete oder VersionenWenn die Infrastruktur als Code behandelt wird, führt dies unweigerlich zu denselben Fehlern und Problemen in der Infrastruktur selbst. Ein typisches Beispiel ist der jüngste Vorfall bei Azure.
Der Azure-Ausfall: Eine Fallstudie in IaC
Vor einigen Tagen kam es zu einer Panne bei Azure, von der Kunden im südlichen Teil Brasiliens betroffen waren. Als großer Cloud-Anbieter folgt Azure dem Motto "Alles ist Code", so dass die Konfiguration von Diensten, Servern, Datenbanken, Endpunkten, Backups und mehr als Code behandelt werden kann. Diese Philosophie erstreckt sich auch auf die Verwaltungsseite von Azure, nicht nur auf die kundenorientierte Cloud, wo Systemadministratoren alles als Code behandeln und die Automatisierung aller Vorgänge ermöglichen.
Vor einigen Tagen testete Azure eine Änderung bei den Verwaltungskomponenten. Das Ziel war es, einige ältere Komponenten durch neuere zu ersetzen, was das Entfernen einiger NuGet-Pakete und die Installation neuer Pakete erforderte. Als Teil der Änderung der NuGet-Pakete musste auch der Code, der auf sie verwies, leicht geändert werden - die Paketnamen waren anders und einige Aufrufkonventionen wurden geändert. Es war nicht gerade ein sofortiger Ersatz.
Die Änderungen wurden in einer Testumgebung mit der Bezeichnung "Ring 0" auf Azure-land (in Anlehnung an den Namen des Modus mit den höchsten Berechtigungen) skriptiert, festgeschrieben, überprüft, getestet und dann bereitgestellt. Sobald in Ring 0 alles gut lief, wurden die Änderungen in Ring 1, der für die Kunden sichtbaren Produktionsumgebung, eingeführt.
Ring 0 ist jedoch, ähnlich wie viele Labor- oder Testumgebungen, eine verkleinerte Version der Produktionsumgebung, ohne dieselbe Belastung, dieselbe Benutzerbasis oder dieselben komplizierten Systeminteraktionen.
Interessanterweise besteht eine relativ routinemäßige Aufgabe, die Azure-Sysadmins in der Produktion durchführen, darin, Snapshots von laufenden Datenbanken zu erstellen, um Fehler zu beheben, ohne echte Arbeitslasten oder Kunden zu beeinträchtigen. Da in einer Laborumgebung ohne echte Produktionsdatenbanken und Probleme keine Snapshots erstellt werden müssen, war Ring 0 snapshotfrei.
Eine der Änderungen in den NuGet-Paketen war eine Änderung in den Funktionen, die Snapshots behandeln.
Intern führt Azure einen Hintergrundjob aus, um alte Snapshots regelmäßig zu löschen. Da es in Ring 0 keine Snapshots gab, wurde in der Testphase nie versucht, welche zu löschen. In der Produktionsumgebung, in der Snapshots vorhanden waren, wurde der Hintergrundjob jedoch mit den Änderungen des NuGet-Pakets ausgeführt, und was einst ein Aufruf zum Entfernen eines Datenbank Snapshot wurde zu einem Aufruf zum Entfernen einer Datenbank Server.
Wie bei einem Autounfall im Zeitlupentempo wurde bei der Ausführung des Auftrags jeder Datenbankserver mit einem ausreichend alten Snapshot gelöscht, während ein Dienst nach dem anderen nicht mehr reagierte.
Die Nachwehen des Azure-Ausfalls
Die Löschung des Servers löste eine Kette tangential zusammenhängender Ereignisse aus:
- In Azure kann ein Kunde einen gelöschten Server nicht selbst wiederherstellen. Dies musste vom Azure-Supportteam erledigt werden.
- Nicht alle betroffenen Server verfügten über dieselbe Art von Backup, wodurch die Wiederherstellungsgeschwindigkeit variierte. Einige waren in der gleichen Region (sprich: Rechenzentrum) gespeichert, während andere geografisch redundant waren, d. h. in verschiedenen Azure-Regionen gespeichert waren. Die Daten mussten vor der Wiederherstellung übertragen werden. Dadurch verlängerte sich die Wiederherstellungszeit.
- Es wurde festgestellt, dass einige Webserver, die auf die gelöschten Datenbankserver angewiesen waren, beim Start einen Test durchführten, um festzustellen, welche Datenbanken verfügbar und erreichbar waren. Diese Anfragen waren an alle Datenbankserver gerichtet und hatten den unbeabsichtigten Nebeneffekt, dass sie den Wiederherstellungsprozess der Datenbankserver beeinträchtigten. Außerdem lösten die Webserver, wenn der Test fehlschlug, sofort einen Neustart aus. Und das geschah. Und es passierte wieder. Und wieder, da diese Datenbanken über einen längeren Zeitraum nicht verfügbar waren.
- Als Vorsichtsmaßnahme wird bei einem fehlgeschlagenen Test eine Technik namens Backoff eingesetzt. Das bedeutet, dass bei einem fehlgeschlagenen Test die Zeitspanne bis zur nächsten Wiederholung immer größer wird. Dieser Anstieg kann linear oder exponentiell sein, und die Idee ist, der anderen Seite genug Zeit zu geben, um sich von der Situation zu erholen, in der sie sich befindet, ohne solche Testanfragen bearbeiten zu müssen. In diesem speziellen Fall hatte dies die unbeabsichtigte Folge, dass Neustarts über eine Stunde dauerten, während sie normalerweise nur Sekunden dauern würden.
- Die Wiederherstellung von Backups war langsam, da die Infrastruktur mit Anfragen überlastet war.
- Sobald ein paar Server wieder online waren, wurden sie schnell vom Kundenverkehr überrollt.
Damit alle Server wieder online gehen konnten, musste der gesamte Datenverkehr unterbrochen werden, bis alle Server wiederhergestellt waren. Diese Verkehrsspitze führte dazu, dass der Ausfall (für die Kunden der betroffenen Azure-Tenants) länger dauerte, als es sonst der Fall gewesen wäre.
Das Ergebnis? Ungefähr 10 Stunden Ausfallzeit, Geschäftsunterbrechungen und eine Menge frustrierter Kunden.
Und das alles entstand durch die Aktualisierung einiger Code-Pakete. Kein Hack, oder ein Feueroder eine andere Gefahr.
Denkanstöße und Lehren
Eine robuste Testumgebung mit der Fähigkeit, die Produktion so genau wie möglich zu imitieren, ist unerlässlich. Exakte Nachbildungen sind schwer zu erreichen, geraten leicht aus dem Takt und sind schwer zu warten. Zu einfache Testumgebungen sind jedoch im Grunde genommen wertlos, da sie nicht die notwendigen Herausforderungen bieten, die in der Produktionsumgebung auftreten.
Wirksame Sicherungs- und Wiederherstellungsstrategien sind von entscheidender Bedeutung. Backups sollten nicht nur verfügbar sein, sondern auch in Live-Wiederherstellungsszenarien getestet worden sein.
Menschliches Versagen ist eine ständige Herausforderung bei der Codeentwicklung. Wir müssen anerkennen, dass in sehr komplexen Systemen kritische Interaktionen und potenzielle Fehler übersehen werden können. Die Systeme müssen noch nicht einmal so komplex sein, damit der Mensch nicht in der Lage ist, alle Feinheiten und Wechselwirkungen zu erfassen. In einer solchen Situation führt die Kodierung unweigerlich zu Problemen.
Die Cloud ist zwar revolutionär, aber auch nicht vor Fehlern gefeit. Menschliches Versagen, Softwarepannen und Hardwarefehler können und werden auftreten. Immer wieder und unerwartet. Und wenn Murphy ein Wörtchen mitzureden hatauch genau zum ungünstigsten Zeitpunkt.
Positiv zu vermerken ist, dass der Vorfall die Hartnäckigkeit der Support- und Betriebsteams von Azure unter Beweis stellte, denen es gelang, gelöschte Ressourcen innerhalb einer relativ kurzen Zeitspanne ohne Datenverlust wiederherzustellen. Der Vorfall unterstreicht, dass die Verwaltung großer Infrastrukturen, insbesondere in Form von Code, zwar eine Herausforderung darstellt, der wahre Maßstab für einen Dienst aber darin besteht, wie schnell er nach einem Fehler reagiert und das Problem behebt.
Abschließend lässt sich sagen, dass es immer ratsam ist, zu automatisieren, wo immer es möglich ist, und sicherzustellen, dass die Testumgebung die Produktionsumgebung so gut wie möglich widerspiegelt. Vorfälle wie diese dienen als wertvolle Erinnerung daran, potenzielle Schwachstellen in unseren Umgebungen zu berücksichtigen, bevor sie zu Fehlern führen.
Es ist auch wichtig, zuerst die trivialen Aufgaben zu automatisieren - z.B., automatische Patch-Verteilung - so dass der Schwerpunkt auf komplexere Vorgänge gelegt werden kann, die mehr Aufmerksamkeit erfordern. Dadurch wird die einzige Ressource, die die Cloud nicht skalieren kann (Gehirnleistung), für wichtigere Aufgaben frei.