Kubernetes in der Praxis

 

PhraseApp ist ein SaaS Produkt mit der Software Internationalisiert wird, um mehrsprachige Webanwendungen anzubieten.
PhraseApp erlediegt die Aufgabe beim Client z.B. Android, Iphone etc. dessen Dateien zu formatieren und zu konvertieren. Der gesamte Übersetzungsmanagementprozess wird über diesen SaaS Dienst abgewickelt.

 

PhraseApp Architektur

 

Bei dieser App handelt es sich um eine klassische monolithische Ruby on Rails Anwendung. Für den Anwender existiert eine Webkomponente wo die Übersetzer darauf arbeiten und wo die Übersetzungen eingepflegt werden. Es existiert eine Entwickler API die es ermöglicht, Übersetzungen per CLI an das System zu übergeben. Zusätzlich existiert eine Komponente für asynchrone Hintergrundprozesse. Das bedeutet wenn z.B. ein Upload getriggert wird bzw. ein neues Übersetzungsfile angelegt wurde, dann liegt diese Datei in einer Warteschlange. Der Benutzer bekommt aber sofort Feedback, dass der Job angenommen worden ist und kann den Status jederzeit einsehen in welchen Zustand sich der Job grade befindet. Diese Tätigkeit übernimmt die asynchrone Worker-Komponente

 

Für die Realisierung dieser Warteschlange wird SQS als SaaS Lösung von Amazon AWS verwendet. Dadurch wird eine fremd gehostet Message Que realisiert. Diese Message Que wird über eine REST API angesteuert, um Nachrichten auf die Warteschlange zu schreiben. Zusätzliche Bestandteile dieser Warteschlange sind Worker, die per long-polling darauf horchen, ob neue Nachrichten existieren, um diese Abzuarbeiten. Für das DBMS wird MySQL als ein relationales Datenbanksystem eingesetzt. Der SearchIndex wird über ElasticSearch realisiert. Das Caching wird mithilfe von Amazon Redis umgesetzt.

 

 

 

Es existieren zwei unterschiedliche Zugriffe auf das System. Entweder als Benutzer über das Web-Frontend oder als Entwickler über den CLI-Client, um auf die Anwendung zuzugreifen. Diese gesamten Komponenten bilden den Monolith der zusätzlich mit OpenSource Software angereichert wird.

 

Probleme

Hauptsächlich enstehen Probleme beim Konfigurationsmanagement, wenn die Software kontinuierlich ausgerollt werden soll.

Bedeutet Betriebssystemversion bzw. Pakete in dem Betriebssysteme oder Bibliotheken aktualisiert werden.

 

Der Releasezyklus ist im Fokus. Der Wunsch ist so schnell wie möglich und so häufig wie möglich zu deployen. 

Für die Horizontale Skalierung gelten bestimmte Traffic-Patterns, die sich auf die Wochentage abbilden lassen, das führt zu Problemen mit der Ressourcenauslastung. Grundsätzlich werden bestimmte EC2 Instanzen nicht zu der gebuchten Tageszeit  derzeitig voll ausgenutzt.

 

Konfigurationsmanagement Probleme

Die klassischen Probleme liegen bei Kernelupdates wenn z.B. ein Security Patch erscheint. Das Betriebsystem sollte aktualisiert werden um neue Features nutzen zu können. Probleme bereiten installierte Server-Packages wie Datenbanktreiber, Bibliotheken die für die Ausführung der Anwendung notwendig sind.

 

Das Update, Securityfixes der dynamischen Laufzeitumgebung für ruby und dessen gems (Bibliotheken).

 

Management beim Quelltext. Es muss sichergestellt werden, dass die richtige Appikationsversion auf allen Servern vorhanden ist und dessen Ressourcen wie Javascript, CSS und Assets. Das gesamte Paket muss konsistent sein.

 

Bei einen Server ist es trivial aber bei mehreren dynamischen Servern, die on-demand aktiviert und deaktiviert werden

ist es wesentlich komplexer zu managen.

 


Updatezyklus

 

Die App wird 1x Pro Tag aktualisiert je nach Deployment.

Die Gems werden 1x Pro Woche aktualisiert.

Bibliotheken für das Betriebssystem werden einmal im Monat aktualisiert.

Die Laufzeitumgebung wird einmal pro Quartal aktualisiert.

Das Betriebssystem wie UBUNTU wird alle 1-2 Jahre aktualisiert.


Releasezyklus

 

 

Das Ziel ist es mehrmals täglich einen Release zu fördern. Es werden dabei kleine und unabhängige Änderungen veröffentlicht. Dabei werden die neuen Features nacheinander ausgerollt der Grund ist falls etwas beim Deployen fehlschlägt ist das Debugging bei mehreren Features die ausgerollt werden wesentlich komplexer. Es wird versucht feingranular und so atomar wie möglich zu Deployen.

Das Deplyoment wird automatisiert ausgeführt.

 

Das Entwicklungsteam nutzt eine Mischung aus SCRUM und Kanban für die Koordination der anstehenden Aufgaben. 

 

Ressourcenauslastung

An dieser Skala werden die täglichen Anfragen abgebildet. bei einer Spitze von 250.000 Anfragen. An den Leistungsspitzen ist deutlich erkennbar das eine zusätzliche Kapazität von  mehr als 50% gefordert ist um die Spitzen auffangen bzw. ausgleichen zu können.

Durch Amazon AWS ist das hinzuschalten und entfernen von neuen Instanzen leicht möglich.

 

 

Continous Delivery

 

Die Entwicklung folgt in ihrer Umsetzung dem Continous Delivery. Der Gedanke ist Software häufiger und schneller zu releasen.

Schnell bedeutet im konkreten Fall, dass nach dem der Entwickler seinen Code  "gepushed" hat, sich dann der Code in GitHub befindet und danach ohne große manuellen Umstände, automatisiert nach erfolgreichen bestehen von Unittests, verfügbar für den Endanwender ist. Der Release soll so einfach wie mögliche gestaltet werden ohne langes Nachdenken. Jeder Entwickler soll zu jederzeit die Möglichkeit haben einen Release zu veröffentlichen.

 

Der Zyklus beginnt mit dem Build nachdem der Code in GitHub gepushed worden ist. Danach finden automatisierte Test statt. Danach wird der Release ausgeführt und im Abschluss findet eine Validierung statt. Bei dieser Validierung wird der Build mit Metriken verglichen für Performance Tests. Ein Mittel um das Continues Delivery ausführen zu könnnen, ist die Containervirtualisierung z.B. Docker. 

 

 

Containervirtualisierung

Die Vorteile von Containervirtualisierung ist das diese sehr leichtgewichtig sind. Container können sehr schnell erstellt oder wieder gelöscht werden. Sie bieten genügen Isolierung bezüglich der CPU. Das bedeutet das es zwischen zwei unterschiedlichen Containern keinen Ressourcenkampf geben kann. Es gibt ein separates Dateisystem, sodass sich die Dateien nicht gegenseitig überschreiben.

Die Netzwerktrennung ist insbesondere für den Fall wichtig wenn auf beide Container, die eine Webapplikation ausführen und diese den Port 80 z.B. für sich beansprucht. Es wird das Ziel einer immutable infrastructure verfolgt. Diese Dev OPs Philosophie bedeutet das an laufenden Systemen nichts mehr verändert wird. Diese werden gelöscht und durch neue ersetzt. Das wird durch VMs besonder leicht ermöglicht.

 

 

Containerorchestrierung

Die Orchestrierung dient der Skalierung, um die Container passend zur Infrastruktur auszurollen. Es geht darum so komfortabel wie möglich eine Menge von Containern auf die entsprechenden Nodes zu verteilen.  Die Gründe für diese Verteilung sind Lastverteilungen, Replikation, Überwachung, Ausfallsicherheit, Service Discovery und eine API die es ermöglicht das Deployment zu programmieren.

 

 

Kubernetes

Kubernetes ist ein Container Orchestrierungstoolkit, Framework. Dieses Framework wird eingesetzt, um verteilte Anwendungen zu bauen. Verteilte Anwendungen bedeuten es sind Anwendungen mit unterschiedlichen Komponenten die untereinander kommunizieren. Mithilfe von Kubernetes wird eine Toolbox dem Entwickler zur Verfügung gestellt, um diese verteilten Anwendungen realisieren zu können. Dabei werden keine größeren Gedanken um die Container gemacht, wie diese, bzw. wo diese grade ausgeführt werden müssen.

 

 

Pods

Pods sind die wichtigsten Komponenten unter Kubernetes. Pods ist eine Menge von eng gekoppelten Container die auf einer Node laufen. Bestehend aus einer Webanwendung und einem Healthcheck der sicherstellt das die Webanwendung läuft. Pods laufen meistens in einem bestimmten Container. Dieser Container hat eine einzige IP Adresse wodurch alle Pods angesprochen werden. Diese Pods teilen sich dadurch das Netzwerkinterface. Pods können ein geteiltes Dateisystem besitzen und werden durch Key Value Paare gelabelt. Mit dem Label können die Pods klassifiziert werden. 

 

Pods - Manifest YAML Konfiguration

 

kind: Pod

apiVersion: v1

metadata:

name: hello

labels:

run: hello

spec:  

containers:  

- name: hello    

image: phraseapp/hello:v1

 

kind 

Ist die Spezifikation das es sich um ein Pod Objekt handelt.

 

apiVersion

Welche API Version verwendet werden soll.

 

spec

In der Spezifikation wird geklärt welche Container bzw welches Image verwendet wird. Zusätzlich werden hier die Netzwerkeinstellungen festgelegt wie der Port und das Protocol

 

Services

Services sind ein logisches Konzept das den Zugriff auf Pods mit einer bestimmten Eigenschaft in dem konkreten Fall mit der gleichen Labelkonfiguration managed. Die Services sind konkrete Objekte in Kubernetes, die über das Loadballancing auf einzelnen Kubernetesnodes über DNS bereitgestellt werden. Sie dienen als Loadballancingregel für die einzelnen Nodes.

Service - Manifest YAML Konfiguration

 

apiVersion: v1

kind: Service

metadata:  

labels:    run: hello

name: hello

spec:  

ports:  

- port: 80    

  targetPort: 8080    

  protocol: TCP  

selector:

run: hello

 

Die Struktur ist die gleiche wie beim Podmanifest. Jeder Service hat einen Namen. Anstelle des Containers wird ein Selector definiert.

Der Selector bedeutet das alle Pods die gelabelt sind mit "run: hello" sind ein Teil des Services. Das bedeutet das im gesamten Cluster unter "hello" über Round Robin und curl nacheinander alle Pods durchgereicht werden.

 

Die Grafik visualisiert ein paar Service-Beispiele. Je spezifischer umso genauer die Pod Auswahl. Wenn unspezifisch definiert wird wie im mittleren Beispiel Service - run=hello werden mehrere Pods gleichzeitig angesprochen.

 

Deployment in Kubernetes

 

Durch das Deployment können deklarative Änderungen an den Pods vorgenommenen werden. Es kann ein Image upgedated werden oder die Betriebsumgebung geändert werden. Zusätzlich kann auch die Pod Konfiguration und dessen Labels angepasst werden.

 

Beim Deployment Prozess wird als erstes der Code nach Github gepushed. An diesen Schritt wird der Pull-Request abgewartet bis er gemerged wird. Dadurch wird ein Push Hook zum Jenkins CI Server getriggert. Jenkins baut dann das Image und pusht es in die AWS Registry. Der Entwickler kann jetzt über die CL eine Liste auslesen, von den möglichen Revisionen, die zum Deployen bereitstehen.

 

Anmerkungen und eigene Meinung

Die beiden Demos haben mir sehr gut gefallen in der Live der Dockerhost angesteuert und ein neuer Container erstellt und ausgeführt wurde, mit den Ziel etwas zu deployen. Die innere Sicht des Containers, wo alle Prozesse sichtbar waren hatte mich besonders interessiert.  Dadurch konnte ein guter aber schneller Einblick in Docker gewonnen werden. Innerhalb der zweiten Demonstration fand ich besonders gut das auf die Services und Pods genauer drauf eingegangen wurde. Es wurde gezeigt wie ein Pod angelegt wird und wie dieser Live ausgeführt wurde. Selbst die Logs konnten von dem Pod ausgelesen werden mit seinen Anwendungen und dessen ruby version.

 

Auch kleinere Kniffe wie die Ausfallsicherheit von Pods sind dargestellt worden indem die Konfiguration "restart - never" angepasst worden ist. Es wurde auch ein Einblick in das gesamte Cluster gewährt das Live ausgeführt war.