Data Science, Machine Learning und KI
Kontakt
Content Hub
Blog Post

Machine Learning Modelle bereitstellen und skalieren mit Kubernetes

  • Autor Jonas Braun
  • Datum 29. Juli 2021
  • Thema
  • Format Blog
  • Zielgruppe Technology
Machine Learning Modelle bereitstellen und skalieren mit Kubernetes

Management Summary

Mit Kubernetes steht uns eine Technologie zur Verfügung, welche in vielerlei Hinsicht die Bereitstellung und Wartung von Anwendungen und Rechenlasten, insbesondere das Training und Hosten von Machine Learning Modellen, enorm vereinfacht. Gleichzeitig ermöglicht sie uns, die benötigten Hardware-Ressourcen dazu an den Bedarf anzupassen, und bietet damit eine skalierbare und kostentransparente Lösung.

Dieser Artikel behandelt zuerst den Weg vom Server hin zu dem Management und der Orchestrierung von Containern: isolierte Anwendungen oder Modelle, welche mit all ihren Anforderungen einmal verpackt werden und im Anschluss fast überall ausgeführt werden können. Unabhängig vom Server können diese mit Kubernetes beliebig repliziert werden und ermöglichen somit aufwandslos und schier nahtlos eine durchgehende Erreichbarkeit ihrer Dienste auch unter hoher Last. Ebenfalls kann ihre Anzahl bis auf einen Mindeststand reduziert werden, wenn die Nachfrage vorübergehend oder periodisch schwindet, um Rechenressourcen anderweitig zu nutzen oder unnötige Kosten zu vermeiden.

Aus den Möglichkeiten dieser Infrastruktur geht ein nützliches Architektur-Paradigma hervor, die Microservices. Ehemals zentralisierte Anwendungen werden so in ihre Funktionalitäten heruntergebrochen, welche ein hohes Maß an Wiederverwendbarkeit bieten. Diese können von unterschiedlichen Diensten angesprochen und verwendet werden und skalieren einzeln je nach internem Bedarf. Ein Beispiel hierfür sind große und komplexe Sprachmodelle im Natural Language Processing, welche den Kontext eines Textes unabhängig von dessen weiterer Verwendung erfassen können, und damit vielen downstream Zwecken zugrunde liegen. Andere Microservices (Modelle), wie zur Text-Klassifikation oder Zusammenfassung, können diese aufrufen und die Teilergebnisse weiterverarbeiten.

Nach einer kurzen Einführung der allgemeinen Begrifflichkeiten und Funktionsweise von Kubernetes, sowie mögliche Anwendungsfälle, richtet sich das Augenmerk auf die am weitesten verbreitete Form Kubernetes zu nutzen: mit Cloud Anbietern wie Google GCP, Amazon AWS oder Microsoft Azure. Diese erlauben sog. Kubernetes Clustern, dynamisch mehr oder weniger Ressourcen zu beanspruchen, wenn gleich die entstehenden Kosten auf pay-per-use Basis absehbar bleiben. Auch weitere gängige Dienste wie Datenspeicher, Versionierung und Networking können von den Anbietern einfach eingebunden werden. Letztlich gibt der Beitrag noch einen Ausblick über Tools und Weiterentwicklungen, welche entweder die Nutzung von Kubernetes noch effizienter machen oder das Verfahren hin zu Serverless Architekturen weiter abstrahieren und vereinfachen.

Inhalt

Einleitung

Über die letzten 20 Jahre sind Unmengen neuer Technologien in der Softwareentwicklung und -Bereitstellung zu Tage gekommen, welche nicht nur die Auswahl an Diensten, Programmiersprachen, Bibliotheken oder ähnliches vervielfacht und diversifiziert haben, sondern gar auch bei vielen Anwendungsfällen oder -Gebieten bis hin zu einem Paradigmenwechsel geführt haben.

Abb. 1: Google Trends Chart, die den zuvor genannten Paradigmenwechsel verdeutlicht.

Betrachtet man so auch die Art und Weise der Bereitstellung von Softwarelösungen, Modellen oder Rechen- und Arbeitslasten über die Jahre, lässt sich erkennen wie auch in diesem Bereich die Neuerungen u.a. zu mehr Flexibilität, Skalierbarkeit und Ressourceneffizienz geführt haben.

Zu Beginn wurden diese als lokale Prozesse direkt auf einem (von mehreren Anwendungen geteilten) Server betrieben, was einige Einschränkungen und Probleme aufwarf: zum einen ist man bei der Auswahl der technischen Werkzeuge an die Begebenheiten der Server und deren Betriebssystem gebunden, zum anderen sind alle Anwendungen, welche auf dem Server gehostet werden, durch dessen Speicher- und Prozessorkapazitäten begrenzt. Somit teilen sie sich nicht nur in Summe die Ressourcen, sondern auch eine eventuelle Prozess-übergreifende Fehleranfälligkeit.

Als erste Weiterentwicklung können Virtuelle Maschinen daraufhin eine weitere Abstraktionsebene bieten: durch das auf dem Server aufgesetzte Emulieren („Virtualisieren“) einer eigenständigen Maschine entsteht für die Entwicklung und das Deployment Modularität und damit größere Freiheit: zum Beispiel in der Wahl des Betriebssystems oder der verwendeten Programmiersprachen und -Bibliotheken. Aus Sicht des „echten“ Servers können die Ressourcen, welche der Anwendung zustehen sollen, besser beschränkt bzw. garantiert werden. Jedoch sind deren Anforderungen auch bedeutend höher, da die Virtuelle Maschine auch das virtuelle Betriebssystem unterhalten muss.

Letztendlich wurde dieses Prinzip durch die Verbreitung von Containern, vor allem Docker, wesentlich verschlankt und vereinfacht. Vereinfacht gesagt baut/konfiguriert man für eine Anwendung oder ein Machine Learning Modell einen eigenen virtuellen, abgegrenzten Server. So enthält jeder Container sein eigenes Dateisystem und gewisse Systembibliotheken, aber nicht das Betriebssystem. Damit wird er technisch zu einem Sandkasten, dessen andere Konfiguration, Code-Abhängigkeiten oder Fehler sich nicht auf den Host-Server auswirken, aber gleichzeitig als relativ „leichtgewichtige“ Prozesse direkt auf diesem laufen können.

_Vergleich virtuelle Maschine und Docker Container Architektur
Abb. 2: Vergleich zwischen Virtueller Maschine und Docker Container Systemarchitektur, Quelle: https://i1.wp.com/www.docker.com/blog/wp-content/uploads/Blog.-Are-containers-..VM-Image-1-1024×435.png?ssl=1

Es besteht also die Möglichkeit, alles für die gewünschte Anwendung zu kopieren, installieren, usw., und dies in einem verpackten Container überall in einem einheitlichen Format bereitzustellen. Dies ist nicht nur für das Produktionsumfeld extrem nützlich, sondern findet bei STATWORX auch gerne in der Entwicklung von komplizierteren Projekten oder der Proof-of-Concept Phase Gebrauch. Zwischenschritte oder -Ergebnisse, wie beispielsweise die Extraktion von Text aus Bildern, können als Container wie ein kleiner Webserver von denjenigen verwendet werden, die an der Weiterverarbeitung des Textes interessiert sind, etwa die Extraktion gewisser zentraler Informationen, oder die Bestimmung von dessen Stimmung oder Absicht.

Diese Unterteilung in sogenannte „Microservices“ mit Hilfe von Containern hilft ungemein bei der Wiederverwendbarkeit der einzelnen Module, bei der Planung und Entwicklung der Architektur komplexer Systeme; sie befreit gleichzeitig die einzelnen Arbeitsschritte von technischen Abhängigkeiten gegenübereinander und erleichtert die Wartungs- und Update-Prozeduren.

Nach diesem kleinen Überblick über die mächtigen und vielseitigen Möglichkeiten der Bereitstellung von Software wird sich der folgende Text damit beschäftigen, wie man diese Container (sprich Anwendungen oder Modelle) verlässlich und skalierbar für Kunden, andere Anwendungen, interne Dienste oder Berechnungen mit Kubernetes bereitstellen kann.

Kubernetes – 8 wesentliche Komponenten

Kubernetes wurde 2014 von Google als open-source Container-Management Software (auch Container-Orchestrierung genannt) vorgestellt. Intern benutzte man bereits seit Jahren eigens entwickelte Tools, um Arbeitslasten und Anwendungen zu verwalten, und sah in der Entwicklung von Kubernetes nicht nur das Zusammenkommen von best practises und lessons learned, sondern auch die Möglichkeit damit ein neues Geschäftsfeld im Cloud Computing zu erschließen.

Der Name Kubernetes (griechisch für Steuermann) wurde angeblich in Bezug auf ein symbolisches Containerschiff ausgewählt, für dessen optimalen Betrieb jener verantwortlich ist.

1.    Nodes

Spricht man von einer Kubernetes-Instanz, wird sie als (Kubernetes) Cluster bezeichnet: dieses besteht aus mehreren Servern, genannt Nodes. Eine davon, die sogenannte Master-Node, ist komplett für den administrativen Betrieb zuständig, und ist die Schnittstelle, welche vom Entwickler angesprochen wird. Alle weiteren, genannt Worker-Nodes, sind zu Beginn unbelegt und damit flexibel einsetzbar. Während Nodes tatsächlich physische Instanzen sind, meist in Rechenzentren, sind die nun folgenden Begrifflichkeiten Konzepte von Kubernetes.

2.    Pods

Soll eine Anwendung auf dem Cluster bereitgestellt werden, wird im einfachsten Fall der gewünschte Container angegeben, und daraufhin (automatisch) ein sogenannter Pod erstellt und einer Node zugewiesen. Der Pod ähnelt hier einfach einem laufenden Container. Sollen gleich mehrere Instanzen der gleichen Anwendung parallel laufen, etwa um bessere Verfügbarkeit zu bieten, kann die Anzahl der Replicas angegeben werden. Hierbei wird die spezifizierte Anzahl an Pods mit jeweils derselben Anwendung auf die Nodes verteilt. Sollte der Bedarf nach der Anwendung trotz Replicas die Kapazitäten übersteigen, können mit dem Horizontal Autoscaler automatisch noch mehr Pods erstellt werden. Besonders bei Deep Learning Modellen mit verhältnismäßig langer Inferenzzeit können hier Metriken wie CPU- oder GPU-Auslastung überwacht werden, und die Anzahl der Pods vergrößert oder verringert werden, um sowohl Kapazitäten als auch Kosten zu optimieren.

Illustration des Autoscaling und der Belegung der Nodes
Abb. 3: Illustration des Autoscaling und der Belegung der Nodes. Die Breite der Balken entspricht dem Ressourcenbedarf der Pods bzw. der Kapazität der Nodes.

Um nicht zu verwirren: Letztlich ist jeder laufende Container, also jede Arbeitslast, ein Pod. Im Falle der Bereitstellung einer Anwendung geschieht das technisch über ein Deployment, zeitlich begrenzte Rechenlasten sind hingegen Jobs. Persistente Speicher wie Datenbanken werden mit StatefulSets verwaltet. Die folgende Abbildung gibt einen Überblick über die Begriffe:

Deployment-Controller
Abb. 4: Was ist was in Kubernetes? Im Deployment wird angegeben was gewünscht ist; der Deployment-Controller kümmert sich um das Erstellen, den Erhalt und das Skalieren der Modell-Container, welche denn als einzelne Pods auf den Nodes laufen. Jobs und StatefulSets funktionieren analog mit ihrem eigenen Controller.

3.    Jobs

Mit Kubernetes Jobs können sowohl einmalige als auch wiederkehrende Jobs (sog. CronJobs) in Form eines Container-Deployment auf dem Cluster ausgeführt werden.

Im einfachsten Fall können diese wie ein Skript gesehen werden, welches für Wartungs- oder Aufbereitungsarbeiten von beispielsweise Datenbanken genutzt werden kann. Des Weiteren verwendet man diese auch zum Batch-Processing, wenn zum Beispiel Deep Learning Modelle auf größere Datenmengen angewandt werden sollen und es sich aber nicht lohnt das Modell durchgehend auf dem Cluster zu halten. Der Modell-Container wird hier eigens hochgefahren, erhält Zugriff auf das gewünschte Dataset, führt seine Inferenz darüber aus, speichert die Ergebnisse und fährt sich herunter. Auch für die Herkunft und anschließende Speicherung der Daten ist man hier flexibel, so können eigene oder Cloud Datenbanken, Bucket/Objekt-Speicher oder auch lokale Daten und Logging-Frameworks angebunden werden.

Für wiederkehrende CronJobs kann ein einfaches Zeitschema spezifiziert werden, sodass beispielsweise nachts bestimmte Kundendaten, -transaktionen oder ähnliches verarbeitet werden. Mit Natural Language Processing können so zum Beispiel nachts automatisch Pressespiegel erstellt werden, welche am folgenden Morgen ausgewertet bereitstehen: Nachrichten zu einem Unternehmen, dessen Branche, Wirtschaftsstandorte, Kunden, usw. können aggregiert oder bezogen werden, mit NLP ausgewertet, zusammengefasst, und mit Stimmungsbildern präsentiert oder nach Themen/Inhalten geordnet werden.

Auch arbeitsintensive ETL (Extract Transform Load) Prozesse können so außerhalb der Geschäftszeiten durchgeführt oder vorbereitet werden.

4.    Rolling Updates

Soll ein Deployment auf die neuste Version gebracht werden, oder muss ein Rollback auf eine ältere Version vollzogen werden, können in Kubernetes Rolling Updates angestoßen werden. Diese garantieren durchgehende Erreichbarkeit der Anwendungen und Modelle innerhalb einer Continuous Integration/Continuous Deployment Pipeline.

Ein solches Rollout kann reibungslos in einem oder wenigen Schritten angestoßen und überwacht werden. Durch eine Rollout-History besteht auch die Möglichkeit, nicht nur auf eine vorherige Containerversion zurückzuspringen, sondern auch die vorherigen Deployment-Parameter wiederhergestellt werden, sprich Mindest- und Höchstanzahl der Nodes, welche Ressourcengruppe (GPU Nodes, CPU Nodes mit wenig/viel RAM,…), Health-Checks usw.

Wird ein Rolling Update angestoßen, werden die jeweiligen bestehenden Pods so lange am Laufen und erreichbar gehalten, bis dieselbe Anzahl an neuen Pods hochgefahren und zugänglich sind. Hier gibt es sowohl Methoden, um zu garantieren, dass keine Requests verloren gehen, wie auch Parameter, die für den Wechsel eine Mindesterreichbarkeit oder einen maximalen Überschuss an Pods regeln.

Illustration eines Rolling Updates
Abb. 5: Illustration eines Rolling Updates.

Die Abbildung 5 veranschaulicht das Rolling Update.

1) Die bisher aktuelle Version einer Anwendung liegt mit 2 Replicas auf dem Kubernetes Cluster und ist gewohnt ansprechbar.

2) Ein Rolling Update auf Version V2 wird gestartet, dieselbe Anzahl an Pods wie für V1 werden erstellt.

3) Sobald die neuen Pods den Zustand „Running“ haben und ggf. Health-Checks absolviert wurden, damit also funktional sind, werden die Container der älteren Version heruntergefahren.

4) Die älteren Pods sind entfernt und die Ressourcen wieder freigegeben.

Der DevOps- und Zeitaufwand ist hierbei marginal, intern ändern sich keine Hostnamen oder ähnliches, während der Dienst aus Sicht der Konsumierenden wie bisher in gewohnter Weise ansprechbar ist (gleiche IP, URL, …) und lediglich auf die neuste Version gebracht wurde.

5.    Platform/Infrastructure as a Service

Natürlich lässt sich ein Kubernetes Cluster auch lokal auf eigener Hardware on-premises einrichten sowie auf teilweise vorgefertigten Lösungen wie DGX Workbenches.

Einige unserer Kunden haben strikte Richtlinien oder Auflagen bezüglich (Data-) Compliance oder Informationssicherheit, und möchten nicht, dass möglicherweise sensible Daten das Unternehmen verlassen. Weiterhin kann so vermieden werden, dass der Datenverkehr über nicht-europäische Knotenpunkte fließt oder generell in ausländischen Rechenzentren landet.

Erfahrungsgemäß ist dies aber nur in einem sehr geringen Anteil der Fall. Durch Verschlüsselung, Rechtemanagement und SLAs der Betreiber erachten wir die Verwendung von Cloud-Diensten und -Rechenzentren als allgemein sicher und verwenden diese auch für größere Projekte. Diesbezüglich sind auch Deployment, Wartung, CI/CD Pipelines dank Methoden der Containerization (Docker) und Abstraktion (Kubernetes) größtenteils identisch und einfach zu verwenden.

Alle großen Cloud-Betreiber wie Google (GCP), Amazon (AWS) und Microsoft (Azure), aber auch kleinere Anbieter und bald sogar spannende neue deutsche Projekte, bieten sehr ähnliche Kubernetes Dienste an. Dadurch wird es noch einfacher, ein Projekt oder Modell bereitzustellen und vor allem zu skalieren, da durch auto-scaling das Cluster je nach Ressourcenbedarf erweitert oder verkleinert werden kann. Dies entbindet uns aus technischer Sicht größtenteils davon die Nachfrage eines Dienstes abschätzen zu müssen, während die Rentabilität und Kostenstruktur gleichbleiben. Weiterhin können die Dienste auch in unterschiedlichen (geographischen) Zonen gehostet und betrieben werden, um schnellste Erreichbarkeit und Redundanz zu garantieren.

6.    Node-Vielfalt

Die Cloud-Betreiber bieten eine große Anzahl unterschiedlicher Node-Typen an, um für alle Anwendungsfälle vom einfacheren Webservice bis hin zu High Performance Computing alle Ressourcenanforderungen zu befriedigen. Besonders im Anwendungsfeld Deep Learning lassen sich so die immer größer werdenden Modelle stets auf der benötigten neuesten Hardware trainieren und bereitstellen.

Während wir beispielsweise für kleinere NLP Zwecke Nodes mit einer durchschnittlichen CPU und geringem Arbeitsspeicher verwenden, lassen sich große Transformer-Modelle im gleichen Cluster auf GPU-Nodes deployen, was deren Verwendung effektiv erst ermöglicht und gleichzeitig die Inferenz (Anwendung des Modells) um Faktor 20 beschleunigen kann. Da neuerdings die Bedeutung dedizierter Hardware für Neuronale Netze stetig zunimmt, bietet Google auch Zugriff auf die eigens entwickelten, für Tensorflow optimierten TPUs an.

Die Organisation und Gruppierung all dieser unterschiedlichen Nodes erfolgt in Kubernetes in sog. Node Pools. Diese können im Deployment ausgewählt bzw. angegeben werden, sodass den Pods der Modelle die richtigen Ressourcen zugeteilt werden.

7.    Cluster Autoscaling

Das Ausmaß der Nutzung von Modellen oder Diensten, intern oder durch Kunden, ist oftmals nicht absehbar oder schwankt zeitlich stark. Mit einem Cluster Autoscaler können automatisch neue Nodes erstellt werden, oder nicht benötigte „leerstehende“ Nodes entfernt werden. Auch hier kann ein Minimum an Nodes angegeben werden, welche immer bereitstehen sollen sowie, wenn gewünscht, auch eine maximale Anzahl, die nicht überschritten werden kann, um ggf. die Kosten zu deckeln.

8.    Anbindung anderer Dienste

Prinzipiell können Cloud Dienste verschiedener Anbieter kombiniert werden, komfortabler und einfacher ist jedoch die Nutzung eines Anbieters (Beispiel Google GCP). Somit können Dienste wie Datenbuckets, Container-Registry, Lambda Funktionen Cloud-intern ohne große Authentifizierungsprozesse eingebunden und verwendet werden. Des Weiteren ist gerade in einer Microservice-Architektur die Netzwerkkommunikation unter den einzelnen Hosts (Anwendungen, Modelle) wichtig und innerhalb eines Anbieters erleichtert. Hier kann auch Zugangskontrolle/RBAC implementiert werden, sowie mehrere Cluster oder Projekte mit einem Virtuellen Netzwerk überbrückt werden, um die Zuständigkeits- und Kompetenzbereiche besser zu trennen.

Umfeld und zukünftige Entwicklungen

Die steigende Nutzung und Verbreitung von Kubernetes haben ein ganzes Umfeld an nützlichen Tools, wie auch Weiterentwicklungen und weitere Abstraktionen mit sich gebracht, welche dessen Verwendung weiter erleichtern.

Tools und Pipelines basierend auf Kubernetes

Mit Kubeflow lässt sich beispielsweise das Training von Machine Learning Modellen als TensorFlow Training Job anstoßen und fertige Modelle mit TensorFlow Serving bereitstellen.

Der ganze Prozess kann auch in eine Pipeline verpackt werden, welche dann mit Verweis auf Trainings-, Validation- und Testdaten in Speicherbuckets das Training verschiedener Modelle durchführt, überwacht, deren Metriken loggt und die Modell-Performance vergleicht. Der Workflow beinhaltet auch die Aufbereitung der Inputdaten, sodass nach erstmaligem Aufbau der Pipeline einfach Experimente zur Exploration von Modellarchitekturen und Hyperparameter-Tuning angestellt werden können

Serverless

Durch Serverless Deployment Verfahren wie Cloud Run oder Amazon Fargate wird ein weiterer Abstraktionsschritt weg von den technischen Anforderungen unternommen. Hiermit können Container binnen Sekunden deployed werden, und skalieren wie Pods auf einem Kubernetes Cluster, ohne dass man dieses überhaupt erstellen oder warten muss. Dieselbe Infrastruktur wurde also noch einmal in ihrer Benutzung vereinfacht. Nach dem Prinzip pay-per-use wird nur die Zeit berechnet, in welcher der Code wirklich aufgerufen und ausgeführt wird.

Fazit

Kubernetes ist heute zu einer zentralen Säule im Machine Learning Deployment geworden. Der Weg von der Daten- und Modellexploration zum Prototyp und schließlich in die Produktion ist durch Bibliotheken wie PyTorch, TensorFlow und Keras zum einen enorm verschlankt und vereinfacht worden. Gleichzeitig können diese Methoden bei Bedarf aber auch enorm detailliert verwendet werden, um maßgeschneiderte Komponenten zu entwickeln oder mittels Transfer Learning bestehende Modelle einzubinden und anzupassen. Container Technologien wie Docker erlauben im Anschluss, das Ergebnis mit all dessen Anforderungen und Abhängigkeiten zu bündeln und ohne weiteren Aufwand fast überall blitzschnell auszuführen. Im letzten Schritt ist deren Bereitstellung, Wartung und Skalierung mit Kubernetes ebenfalls ungemein vereinfacht und leistungsfähig geworden.

All dies erlaubt uns eigene Produkte sowie Lösungen für Kunden strukturiert zu entwickeln:

  • Die Komponenten und die Rahmeninfrastruktur haben eine hohe Wiederverwendbarkeit
  • Mit verhältnismäßig geringem Zeit- und Kostenaufwand kann ein erster Meilenstein oder Proof-of-Concept erreicht werden
  • Die weiterführende Entwicklungsarbeit folgt auf natürliche Weise weiter diesem Prozess
  • Fertige Deployments skalieren ohne zusätzlichen Aufwand, mit Kosten proportional zum Bedarf
  • Daraus folgt eine verlässliche Plattform mit planbarer Kostenstruktur

Wenn Sie sich im Anschluss an diesen Artikel weiter über einige zentrale Komponenten informieren möchten, haben wir hier noch einige interessante Beiträge über:

Quellen

 

Jonas Braun

Erfahre mehr!

Als eines der führenden Unternehmen im Bereich Data Science, Machine Learning und KI begleiten wir Sie in die datengetriebene Zukunft. Erfahren Sie mehr über statworx und darüber, was uns antreibt.
Über uns