Florian Balling

Geschätzte Lesezeit 8 Minuten

Techblog

Zero-Downtime Austausch eines Kubernetes Ingress Controllers

“Unsere Kunden erwarten unsere Services zu jeder Zeit, egal wo sie gerade sind. Zero Downtime Deployments sind für uns daher unumgänglich“, sagt Axel Becker, Head of IT Operations bei DER Touristik online GmbH. Wie das gelingen kann, zeigt unser Lead Software Engineer Florian Balling in seinem Blogpost.

Controller-Austausch ohne Ausfallzeit

Viele Anwendungen in der Cloud werden heute innerhalb eines Kubernetes Clusters betrieben. Als Container-Orchestrierungsplattform unterstützt Kubernetes Entwickler:innen hinsichtlich Skalierung, Ausfallsicherheit und Netzwerktechnik.
Doch wie tauscht man im laufenden Betrieb den Ingress Controller, ohne Ausfallzeiten in Kauf nehmen zu müssen? Für dieses Problem im DER Touristik Projekt taugte keine Standardlösung.

Stattdessen tauschten wir unseren Ingress Controller ohne Ausfallzeit gegen einen anderen Ingress Controller aus. Die umgesetzte Lösung basiert auf einer Kombination aus aus den modernen Deployment-Strategien blue green deployment und canary release, um sicher und ausfallfrei zu migrieren. Dazu setzten wir ausschließlich auf einfache Konzepte wie header based routing, weight based routing und einen Parallelbetrieb, wodurch sich die gewonnenen Erkenntnisse leicht auf andere Projekte übertragen ließen.

“Unsere Kunden erwarten unsere Services zu jeder Zeit, egal wo sie gerade sind. Zero Downtime Deployments sind für uns daher unumgänglich.”

Axel Becker, Head of Operations, DER Touristik Online GmbH

Der Ingress Controller

Stellt ein Kunde eine Anfrage an eine Webseite “www.example.com”, deren Server in einem Kubernetes Cluster liegt, wird die Anfrage aus Cluster-Sicht als ingress request oder auch eintreffenden Anfrage bezeichnet.
In Kubernetes Clustern werden diese ingress requests an einen Cluster-internen Service durch den Ingress-Controller bearbeitet. Im Prinzip liest ein Ingress Controller alle Ingress Definitionen (Kubernetes Objekte) ein und konfiguriert basierend darauf seine Routing Regeln. Eine solche Regel könnte lauten:

“Ankommende Anfragen für www.example.com weiterleiten an den Cluster-internen Service namens example-service.”

Der Ingress Controller als Single Point of Failure

Gibt es gerade keine Instanz eines Ingress Controllers, z.B. durch einen Ausfall, so kann das Cluster keine Anfrage von außen mehr bedienen und die Webanwendung scheint von außen als offline. Eine solche Situation geht schnell mit hohen Verlusten einher und wird daher, so gut es geht, vermieden.

Durch eine neue Anforderung, die unser aktueller Ingress Controller Traefik nicht erfüllen konnte, waren wir gezwungen, auf einen anderen Ingress Controller zu wechseln (Nginx). Wird eine Ausfallzeit akzeptiert, so lässt sich der Wechsel einfach realisieren. Das Vorgehen sieht dann wie folgt aus:

  1. Wartungsseite live schalten (ala “Wir sind in Kürze wieder für sie da …”)
  2. traefik abbauen
  3. Nginx aufbauen
  4. Eigentliche Seite live schalten

Wir waren aber auf der Suche nach einem Verfahren ohne Ausfallzeiten, um damit verbundene Verluste zu vermeiden.

Der Grund für den Wechsel des Ingress-Controller

Ein Ingress-Controller erfüllt nicht nur den erwähnten Zweck, Ingress-Anfragen zu routen, sondern kann auch Redirect-Antworten senden. Ein Redirect ist eine Http Antwort, die den Anfragenden über ein aktualisiertes Ziel informiert.

So kann sich der Pfad zu einer Ressource im Laufe des Lebenszyklus einer Webanwendung ändern, ihr alter Pfad aber schon im Web verteilt sein (Verlinkungen anderer Seiten, Crawler Caches). Ein Nutzer folgt einem veralteten Link auf einer Seite und wird mit einem Redirect trotzdem auf die neue korrekte Seite umgeleitet:

  1. Nutzer klickt auf Link example.com/car1
  2. Browser schickt eine Anfrage an example.com/car1
  3. Ingress-Controller erhält Anfrage an example.com und schickt Redirect an example.com/cars/1
  4. Browser erhält Antwort “Redirect to example.com/cars/1
  5. Browser schickt Request an example.com/cars/1
  6. Ingress Controller erhält Anfrage an example.com/cars/1 und leitet Anfrage weiter an Cluster internen Service example-service
  7. example-service schickt Antwort an Browser des Nutzers
  8. Browser erhält Antwort für example.com/cars/1 und zeigt diese Antwort (Webseite) an

In Traefik wird ein Redirect durch eine sogenannte redirect middleware konfiguriert. Diese Middleware enthält einen regulären Ausdruck, der die angefragte Adresse beschreibt und ein weiterer beschreibt die Adresse, mit der geantwortet werden soll. Bei wenigen zu konfigurierenden Redirects ist das kein Problem und lässt sich auch gut mit diesen middlewares umsetzen.

Gibt es wie in unserem Fall jedoch mehrere tausend Redirects, müssen wir mit Performance Problemen kämpfen. Unsere Wahl für eine Alternative fiel auf nginx, da er wenig Performance Overhead im Zusammenhang mit Redirects produziert.

Ausgangssituation

In der Ausgangssituation sah unsere Infrastruktur wie folgt aus:

Wir betreiben unsere Services in einem Kubernetes Cluster gehostet auf AWS.

Jede Kundenanfrage läuft über den AWS Load Balancer, der sie, basierend auf gewissen Regeln, an eine target group weiterleitet. In unserem Fall werden alle Anfragen an die traefik target group weitergeleitet, in der zwei Instanzen von Traefik aus unserem Kubernetes Cluster registriert sind. Die ankommenden Anfragen werden gleichmäßig auf die zwei Instanzen verteilt und schlussendlich von einer Traefik Instanz an den richtigen Service im Cluster weitergeleitet.

Migrationsphase

Die Migrationsphase von Traefik auf Nginx lässt sich in mehrere Schritte aufteilen.

1. Nginx Ingress Controller deployen

Nginx wurde parallel zu Traefik als zweiter Ingress-Controller deployed.

2. Nginx Ingress Controller erreichbar machen

Um den Kundenverkehr nicht zu stören, werden die neuen nginx Instanzen in einer neuen target group des Load Balancers registriert (siehe Grafik). Jetzt ist es möglich, eine Regel zu definieren, mit der anhand der Anfrage entschieden werden kann, ob Zugriff auf das Cluster per Traefik oder Nginx gewünscht ist.

Um nginx mit einer ausgewählten Nutzerbasis, in unserem Fall Kolleg:innen aus der Qualitätssicherung und uns Platform Engineers, zur Verfügung stellen zu können, verwendeten wir eine Regel basierend auf einem Header use-nginx. Durch header based routing ist hier die canary release Strategie umgesetzt, bei der Änderungen an der Software erstmal einer kleinen Nutzergruppe zur Verfügung gestellt wird.

Die zweite Regel routet jede Anfrage, sofern sie nicht von der ersten Regel abgedeckt wird, über Traefik in unser Cluster. Da diese Regel aber jetzt gewichtsbasiert ist, also die Möglichkeit bietet, einen Teil der Anfragen über den einen Weg und alle anderen über den anderen Weg ins Cluster zu schicken, lassen sich hiermit auch die Kundenanfragen langsam von Traefik auf Nginx verschieben (canary release).

Diese zweite Regel entkoppelt das Deployment und das Release von nginx und macht einen Rollback möglich: bei Problemen nach dem Release von Nginx wieder auf Traefik zurückzuschalten (blue green deployment).

3. Traefik Konfiguration auf Nginx anwenden

Um nginx mit der gleichen Konfiguration zu bestücken, wie sie in Traefik vorliegt, werden alle Ingress Ressourcen dupliziert und weitere Konfiguration wie Basic Auth Credentials oder Redirects eingepflegt.

4. Qualität sicher stellen

Da Nginx nun von außen unter der Verwendung des Headers erreichbar ist, kann die Funktionalität durch automatisierte Tests und manuelle Abnahmen sichergestellt werden. Auch nichtfunktionale Kriterien wie Leistung und Zuverlässigkeit von nginx lassen sich jetzt z.B. durch Last-Tests überprüfen.

5. Release

Ist genug Sicherheit vorhanden, so dass Nginx alle bestehenden Anforderungen erfüllt, erfolgt das Release an die Endkunden, indem die zweite Routing Regel im Load Balancer 100% der Anfragen an Nginx weiterleitet.

Nach der Migration

In den ersten Tagen nach der Migration ist die Wahrscheinlichkeit für Fehler am höchsten. Daher bietet es sich an, genug Zeit vergehen zu lassen, bevor mit den Abbauarbeiten der alten Lösung bzw. des Fallbacks begonnen wird. Ist man sicher, dass die neue Lösung trägt, können alle Ressourcen von und für Traefik abgebaut werden.

Abschließende Gedanken

Das hier vorgestellte Vorgehen ermöglicht die Nutzung moderner Deployment Strategien wie canary release und blue green deployment, um mit hoher Sicherheit und ausfallfrei zentrale Komponenten auszutauschen. Der Charme entsteht meiner Meinung nach durch die Einfachheit und die vielseitige Verwendbarkeit, zumal nur Standardkomponenten verwendet werden und keine komplexen technischen Lösungen wie service meshes.

Wir waren froh, einen weiteres Big Bang Release umgehen zu können und begeistert davon, wie reibungslos der Austausch unseres Ingress Controller abgelaufen ist.


About the author

Florian Balling

Lead Software Engineer

Seine Arbeit als Cloud Platform Engineer veranschaulicht Florian gern mit einer Analogie zum Städtebau: „Ich entwickle die grundliegenden Teile der virtuellen Städte (Softwarelandschaften): angefangen von den Fundamenten für alle Gebäude (Hosting-Plattformen), Straßen und Kanäle (Netzwerke) und Verwaltungsgebäude (zentrale Dienste). Zudem entwickle und verteile ich Werkzeuge an die anderen Bauherren (Softwareentwickler:innen), die diesen die Arbeit erleichtern (Pipelines und CI Tooling). Schließlich richte ich Überwachungen ein, so dass die Teammitglieder schnell reagieren können, wenn es irgendwo einen Notfall in der Stadt gibt (Observability).