Scala skalieren: Dockerisieren mit Kubernetes
Veröffentlicht: 2022-03-11Kubernetes ist das neue Kind auf dem Block und verspricht, Anwendungen in der Cloud bereitzustellen und schneller zu skalieren. Heutzutage ist es bei der Entwicklung für eine Microservices-Architektur ziemlich üblich, Scala zum Erstellen von API-Servern zu wählen.
Wenn Sie eine Scala -Anwendung in Ihren Plänen haben und diese in eine Cloud skalieren möchten, dann sind Sie hier richtig. In diesem Artikel werde ich Schritt für Schritt zeigen, wie man eine generische Scala-Anwendung nimmt und Kubernetes mit Docker implementiert, um mehrere Instanzen der Anwendung zu starten. Das Endergebnis wird eine einzelne Anwendung sein, die als mehrere Instanzen bereitgestellt und von Kubernetes mit Lastenausgleich versehen wird.
All dies wird durch einfaches Importieren des Kubernetes-Quellkits in Ihre Scala-Anwendung implementiert. Bitte beachten Sie, dass das Kit viele komplizierte Details in Bezug auf Installation und Konfiguration verbirgt, aber es ist klein genug, um lesbar und leicht verständlich zu sein, wenn Sie analysieren möchten, was es tut. Der Einfachheit halber stellen wir alles auf Ihrem lokalen Rechner bereit. Dieselbe Konfiguration eignet sich jedoch für eine reale Cloud-Bereitstellung von Kubernetes.
Was ist Kubernetes?
Bevor wir auf die blutigen Details der Implementierung eingehen, lassen Sie uns besprechen, was Kubernetes ist und warum es wichtig ist.
Vielleicht haben Sie schon von Docker gehört. In gewissem Sinne ist es eine leichtgewichtige virtuelle Maschine.
Aus diesen Gründen ist es bereits eines der am weitesten verbreiteten Tools für die Bereitstellung von Anwendungen in Clouds. Ein Docker-Image ist ziemlich einfach und schnell zu erstellen und zu duplizieren, viel einfacher als eine herkömmliche virtuelle Maschine wie VMWare, VirtualBox oder XEN.
Kubernetes ergänzt Docker und bietet eine vollständige Umgebung für die Verwaltung von dockerisierten Anwendungen. Durch die Verwendung von Kubernetes können Sie Hunderte oder sogar Tausende von Docker-Anwendungen einfach bereitstellen, konfigurieren, orchestrieren, verwalten und überwachen.
Kubernetes ist ein von Google entwickeltes Open-Source-Tool, das von vielen anderen Anbietern übernommen wurde. Kubernetes ist nativ auf der Google-Cloud-Plattform verfügbar, aber auch andere Anbieter haben es für ihre OpenShift-Cloud-Dienste übernommen. Es ist auf Amazon AWS, Microsoft Azure, RedHat OpenShift und noch mehr Cloud-Technologien zu finden. Wir können sagen, dass es gut positioniert ist, um ein Standard für die Bereitstellung von Cloud-Anwendungen zu werden.
Voraussetzungen
Nachdem wir nun die Grundlagen behandelt haben, prüfen wir, ob Sie die gesamte erforderliche Software installiert haben. Zunächst einmal benötigen Sie Docker. Wenn Sie entweder Windows oder Mac verwenden, benötigen Sie die Docker Toolbox. Wenn Sie Linux verwenden, müssen Sie das von Ihrer Distribution bereitgestellte Paket installieren oder einfach den offiziellen Anweisungen folgen.
Wir werden in Scala programmieren, einer JVM-Sprache. Sie benötigen natürlich das Java Development Kit und das Tool scala SBT, das im globalen Pfad installiert und verfügbar ist. Wenn Sie bereits ein Scala-Programmierer sind, haben Sie diese Tools wahrscheinlich bereits installiert.
Wenn Sie Windows oder Mac verwenden, erstellt Docker standardmäßig eine virtuelle Maschine namens default mit nur 1 GB Arbeitsspeicher, was für die Ausführung von Kubernetes zu klein sein kann. Nach meiner Erfahrung hatte ich Probleme mit den Standardeinstellungen. Ich empfehle, dass Sie die VirtualBox-GUI öffnen, die default Ihrer virtuellen Maschine auswählen und den Speicher auf mindestens 2048 MB ändern.
Die Anwendung zum Clusterisieren
Die Anweisungen in diesem Lernprogramm können für alle Scala-Anwendungen oder -Projekte gelten. Damit dieser Artikel etwas „Fleisch“ zum Arbeiten hat, habe ich ein Beispiel ausgewählt, das sehr oft verwendet wird, um einen einfachen REST-Microservice in Scala namens Akka HTTP zu demonstrieren. Ich empfehle Ihnen, das Quellkit auf das vorgeschlagene Beispiel anzuwenden, bevor Sie versuchen, es in Ihrer Anwendung zu verwenden. Ich habe das Kit mit der Demoanwendung getestet, kann aber nicht garantieren, dass es keine Konflikte mit Ihrem Code gibt.
Also beginnen wir zuerst damit, die Demo-Anwendung zu klonen:
git clone https://github.com/theiterators/akka-http-microserviceTesten Sie als nächstes, ob alles richtig funktioniert:
cd akka-http-microservice sbt run Greifen Sie dann auf http://localhost:9000/ip/8.8.8.8 , und Sie sollten so etwas wie im folgenden Bild sehen:
Hinzufügen des Source-Kits
Jetzt können wir das Source-Kit mit etwas Git-Magie hinzufügen:
git remote add ScalaGoodies https://github.com/sciabarra/ScalaGoodies git fetch --all git merge ScalaGoodies/kubernetesDamit haben Sie die Demo einschließlich des Source-Kits und können es ausprobieren. Oder Sie können sogar den Code von dort kopieren und in Ihre Anwendung einfügen.
Sobald Sie die Dateien in Ihren Projekten zusammengeführt oder kopiert haben, können Sie beginnen.
Kubernetes starten
Nachdem Sie das Kit heruntergeladen haben, müssen wir die erforderliche kubectl Binärdatei herunterladen, indem Sie Folgendes ausführen:
bin/install.sh Dieses Installationsprogramm ist (hoffentlich) intelligent genug, um je nach System die richtige kubectl Binärdatei für OSX, Linux oder Windows herunterzuladen. Beachten Sie, dass das Installationsprogramm auf den Systemen funktionierte, die ich besitze. Bitte melden Sie alle Probleme, damit ich das Kit reparieren kann.
Sobald Sie die kubectl Binärdatei installiert haben, können Sie das gesamte Kubernetes in Ihrem lokalen Docker starten. Lauf einfach:
bin/start-local-kube.shBei der ersten Ausführung lädt dieser Befehl die Images des gesamten Kubernetes-Stacks und eine lokale Registrierung herunter, die zum Speichern Ihrer Images erforderlich ist. Es kann einige Zeit dauern, also haben Sie bitte etwas Geduld. Beachten Sie auch, dass es direkte Zugänge zum Internet benötigt. Wenn Sie sich hinter einem Proxy befinden, stellt dies ein Problem dar, da das Kit keine Proxys unterstützt. Um es zu lösen, müssen Sie die Tools wie Docker, Curl usw. konfigurieren, um den Proxy zu verwenden. Es ist kompliziert genug, dass ich empfehle, einen temporären uneingeschränkten Zugang zu erhalten.
Angenommen, Sie konnten alles erfolgreich herunterladen, um zu überprüfen, ob Kubernetes einwandfrei läuft, können Sie den folgenden Befehl eingeben:
bin/kubectl get nodesDie erwartete Antwort lautet:
NAME STATUS AGE 127.0.0.1 Ready 2mBeachten Sie, dass das Alter natürlich variieren kann. Da das Starten von Kubernetes einige Zeit in Anspruch nehmen kann, müssen Sie den Befehl möglicherweise einige Male aufrufen, bevor Sie die Antwort sehen. Wenn Sie hier keine Fehler erhalten, herzlichen Glückwunsch, Sie haben Kubernetes auf Ihrem lokalen Computer eingerichtet und ausgeführt.
Dockerisieren Ihrer Scala-App
Nachdem Sie Kubernetes eingerichtet und ausgeführt haben, können Sie Ihre Anwendung darin bereitstellen. Früher, vor Docker, mussten Sie einen ganzen Server bereitstellen, um Ihre Anwendung auszuführen. Mit Kubernetes müssen Sie zum Bereitstellen Ihrer Anwendung nur Folgendes tun:
- Erstellen Sie ein Docker-Image.
- Schieben Sie es in eine Registrierung, von wo aus es gestartet werden kann.
- Starten Sie die Instanz mit Kubernetes, die das Image aus der Registrierung übernimmt.
Glücklicherweise ist es viel weniger kompliziert, als es aussieht, besonders wenn Sie das SBT-Build-Tool verwenden, wie es viele tun.
Im Kit habe ich zwei Dateien enthalten, die alle notwendigen Definitionen enthalten, um ein Image zu erstellen, das Scala-Anwendungen ausführen kann, oder zumindest das, was zum Ausführen der Akka-HTTP-Demo benötigt wird. Ich kann nicht garantieren, dass es mit anderen Scala-Anwendungen funktioniert, aber es ist ein guter Ausgangspunkt und sollte für viele verschiedene Konfigurationen funktionieren. Die Dateien, die zum Erstellen des Docker-Images gesucht werden müssen, sind:
docker.sbt project/docker.sbt Schauen wir uns an, was in ihnen steckt. Die Datei project/docker.sbt enthält den Befehl zum Importieren des sbt-docker :
addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.4.0") Dieses Plugin verwaltet das Erstellen des Docker-Images mit SBT für Sie. Die Docker-Definition befindet sich in der Datei docker.sbt und sieht folgendermaßen aus:
imageNames in docker := Seq(ImageName("localhost:5000/akkahttp:latest")) dockerfile in docker := { val jarFile: File = sbt.Keys.`package`.in(Compile, packageBin).value val classpath = (managedClasspath in Compile).value val mainclass = mainClass.in(Compile, packageBin).value.getOrElse(sys.error("Expected exactly one main class")) val jarTarget = s"/app/${jarFile.getName}" val classpathString = classpath.files.map("/app/" + _.getName) .mkString(":") + ":" + jarTarget new Dockerfile { from("anapsix/alpine-java:8") add(classpath.files, "/app/") add(jarFile, jarTarget) entryPoint("java", "-cp", classpathString, mainclass) } }Um die Bedeutung dieser Datei vollständig zu verstehen, müssen Sie Docker gut genug kennen, um diese Definitionsdatei zu verstehen. Wir gehen jedoch nicht auf die Details der Docker-Definitionsdatei ein, da Sie sie nicht gründlich verstehen müssen, um das Image zu erstellen.

die SBT übernimmt die Sammlung aller Dateien für Sie.
Beachten Sie, dass der Klassenpfad automatisch durch den folgenden Befehl generiert wird:
val classpath = (managedClasspath in Compile).value Im Allgemeinen ist es ziemlich kompliziert, alle JAR-Dateien zu sammeln, um eine Anwendung auszuführen. Mit SBT wird die Docker-Datei mit add(classpath.files, "/app/") generiert. Auf diese Weise sammelt SBT alle JAR-Dateien für Sie und erstellt ein Dockerfile zum Ausführen Ihrer Anwendung.
Die anderen Befehle sammeln die fehlenden Teile, um ein Docker-Image zu erstellen. Das Image wird mithilfe eines vorhandenen Image-APT zum Ausführen von Java-Programmen erstellt ( anapsix/alpine-java:8 , im Internet im Docker Hub verfügbar). Andere Anweisungen fügen die anderen Dateien hinzu, um Ihre Anwendung auszuführen. Schließlich können wir es ausführen, indem wir einen Einstiegspunkt angeben. Beachten Sie auch, dass der Name absichtlich mit localhost:5000 beginnt, da localhost:5000 dort ist, wo ich die Registrierung im start-kube-local.sh Skript installiert habe.
Erstellen des Docker-Images mit SBT
Um das Docker-Image zu erstellen, können Sie alle Details des Dockerfiles ignorieren. Sie müssen nur Folgendes eingeben:
sbt dockerBuildAndPush Das sbt-docker in erstellt dann ein Docker-Image für Sie, lädt alle erforderlichen Teile aus dem Internet herunter und pusht es dann zusammen mit der Kubernetes-Anwendung in localhost in eine Docker-Registrierung, die zuvor gestartet wurde. Sie müssen also nur noch ein wenig warten, bis Ihr Bild gekocht und fertig ist.
Beachten Sie, dass Sie bei Problemen am besten alles auf einen bekannten Zustand zurücksetzen, indem Sie die folgenden Befehle ausführen:
bin/stop-kube-local.sh bin/start-kube-local.sh Diese Befehle sollten alle Container stoppen und korrekt neu starten, damit Ihre Registrierung bereit ist, das von sbt und gepushte Image zu empfangen.
Starten des Dienstes in Kubernetes
Jetzt, da die Anwendung in einen Container gepackt und in eine Registrierung geschoben wurde, können wir sie verwenden. Kubernetes verwendet die Befehlszeile und Konfigurationsdateien, um den Cluster zu verwalten. Da Befehlszeilen sehr lang werden können und die Schritte auch replizieren können, verwende ich hier die Konfigurationsdateien. Alle Samples im Source Kit befinden sich im Ordner kube .
Unser nächster Schritt besteht darin, eine einzelne Instanz des Images zu starten. Ein laufendes Image wird in der Kubernetes-Sprache als Pod bezeichnet. Lassen Sie uns also einen Pod erstellen, indem Sie den folgenden Befehl aufrufen:
bin/kubectl create -f kube/akkahttp-pod.ymlSie können die Situation jetzt mit dem Befehl überprüfen:
bin/kubectl get podsDas solltest du sehen:
NAME READY STATUS RESTARTS AGE akkahttp 1/1 Running 0 33s k8s-etcd-127.0.0.1 1/1 Running 0 7d k8s-master-127.0.0.1 4/4 Running 0 7d k8s-proxy-127.0.0.1 1/1 Running 0 7dDer Status kann tatsächlich anders sein, z. B. „ContainerCreating“, es kann einige Sekunden dauern, bis er zu „Running“ wird. Außerdem können Sie einen anderen Status wie „Fehler“ erhalten, wenn Sie beispielsweise vergessen haben, das Image zuvor zu erstellen.
Sie können auch mit dem folgenden Befehl überprüfen, ob Ihr Pod ausgeführt wird:
bin/kubectl logs akkahttpSie sollten eine Ausgabe sehen, die etwa so endet:
[DEBUG] [05/30/2016 12:19:53.133] [default-akka.actor.default-dispatcher-5] [akka://default/system/IO-TCP/selectors/$a/0] Successfully bound to /0:0:0:0:0:0:0:0:9000Jetzt haben Sie den Dienst im Container eingerichtet und ausgeführt. Der Dienst ist jedoch noch nicht erreichbar. Dieses Verhalten ist Teil des Designs von Kubernetes. Ihr Pod wird ausgeführt, aber Sie müssen ihn explizit verfügbar machen. Andernfalls soll der Dienst intern sein.
Erstellen eines Dienstes
Das Erstellen eines Dienstes und das Überprüfen des Ergebnisses ist eine Frage der Ausführung:
bin/kubectl create -f kube/akkahttp-service.yaml bin/kubectl get svcSie sollten so etwas sehen:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE akkahttp-service 10.0.0.54 9000/TCP 44s kubernetes 10.0.0.1 <none> 443/TCP 3m Beachten Sie, dass der Port unterschiedlich sein kann. Kubernetes hat dem Dienst einen Port zugewiesen und ihn gestartet. Wenn Sie Linux verwenden, können Sie den Browser direkt öffnen und http://10.0.0.54:9000/ip/8.8.8.8 , um das Ergebnis anzuzeigen. Wenn Sie Windows oder Mac mit Docker Toolbox verwenden, ist die IP lokal für die virtuelle Maschine, auf der Docker ausgeführt wird, und leider immer noch nicht erreichbar.
Ich möchte hier betonen, dass dies kein Problem von Kubernetes ist, sondern eine Einschränkung der Docker Toolbox, die wiederum von den Einschränkungen abhängt, die von virtuellen Maschinen wie VirtualBox auferlegt werden, die sich wie ein Computer in einem anderen Computer verhalten. Um diese Einschränkung zu überwinden, müssen wir einen Tunnel erstellen. Um die Dinge einfacher zu machen, habe ich ein weiteres Skript eingefügt, das einen Tunnel auf einem beliebigen Port öffnet, um jeden von uns bereitgestellten Dienst zu erreichen. Sie können den folgenden Befehl eingeben:
bin/forward-kube-local.sh akkahttp-service 9000 Beachten Sie, dass der Tunnel nicht im Hintergrund läuft, Sie müssen das Terminalfenster geöffnet lassen, solange Sie es brauchen, und schließen, wenn Sie den Tunnel nicht mehr brauchen. Während der Tunnel läuft, können Sie http://localhost:9000/ip/8.8.8.8 und schließlich sehen, wie die Anwendung in Kubernetes läuft.
Letzter Schliff: Skalierung
Bisher haben wir unsere Anwendung „einfach“ in Kubernetes gestellt. Dies ist zwar eine aufregende Leistung, trägt aber nicht zu sehr zu unserem Einsatz bei. Wir ersparen uns den Aufwand, auf einem Server hochzuladen und zu installieren und dafür einen Proxy-Server zu konfigurieren.
Wo Kubernetes glänzt, ist die Skalierung. Sie können zwei, zehn oder hundert Instanzen unserer Anwendung bereitstellen, indem Sie nur die Anzahl der Replikate in der Konfigurationsdatei ändern. Also machen wir's.
Wir werden den einzelnen Pod stoppen und stattdessen eine Bereitstellung starten. Lassen Sie uns also die folgenden Befehle ausführen:
bin/kubectl delete -f kube/akkahttp-pod.yml bin/kubectl create -f kube/akkahttp-deploy.yamlÜberprüfen Sie als Nächstes den Status. Auch hier können Sie es einige Male versuchen, da die Bereitstellung einige Zeit in Anspruch nehmen kann:
NAME READY STATUS RESTARTS AGE akkahttp-deployment-4229989632-mjp6u 1/1 Running 0 16s akkahttp-deployment-4229989632-s822x 1/1 Running 0 16s k8s-etcd-127.0.0.1 1/1 Running 0 6d k8s-master-127.0.0.1 4/4 Running 0 6d k8s-proxy-127.0.0.1 1/1 Running 0 6d Jetzt haben wir zwei Pods, nicht einen. Dies liegt daran, dass in der von mir bereitgestellten Konfigurationsdatei der Wert replica: 2 mit zwei verschiedenen vom System generierten Namen vorhanden ist. Ich gehe nicht auf die Details der Konfigurationsdateien ein, da der Umfang des Artikels lediglich eine Einführung für Scala-Programmierer zum Start in Kubernetes ist.
Jedenfalls sind jetzt zwei Pods aktiv. Interessant ist, dass der Service derselbe ist wie zuvor. Wir haben den Dienst so konfiguriert, dass der Lastausgleich zwischen allen Pods mit der Bezeichnung akkahttp . Das bedeutet, dass wir den Dienst nicht erneut bereitstellen müssen, aber wir können die einzelne Instanz durch eine replizierte ersetzen.
Wir können dies überprüfen, indem wir den Proxy erneut starten (wenn Sie Windows verwenden und ihn geschlossen haben):
bin/forward-kube-local.sh akkahttp-service 9000Dann können wir versuchen, zwei Terminalfenster zu öffnen und die Protokolle für jeden Pod anzuzeigen. Zum Beispiel im ersten Typ:
bin/kubectl logs -f akkahttp-deployment-4229989632-mjp6uUnd im zweiten Typ:
bin/kubectl logs -f akkahttp-deployment-4229989632-s822xBearbeiten Sie die Befehlszeile natürlich entsprechend mit den Werten, die Sie in Ihrem System haben.
Versuchen Sie nun, mit zwei verschiedenen Browsern auf den Dienst zuzugreifen. Sie sollten damit rechnen, dass die Anfragen zwischen den mehreren verfügbaren Servern aufgeteilt werden, wie in der folgenden Abbildung:
Fazit
Heute haben wir kaum an der Oberfläche gekratzt. Kubernetes bietet viel mehr Möglichkeiten, darunter automatische Skalierung und Neustart, inkrementelle Bereitstellungen und Volumes. Darüber hinaus ist die Anwendung, die wir als Beispiel verwendet haben, sehr einfach, zustandslos, wobei sich die verschiedenen Instanzen nicht kennen müssen. In der realen Welt müssen verteilte Anwendungen einander kennen und Konfigurationen entsprechend der Verfügbarkeit anderer Server ändern. Tatsächlich bietet Kubernetes einen verteilten Schlüsselspeicher ( etcd ), damit verschiedene Anwendungen miteinander kommunizieren können, wenn neue Instanzen bereitgestellt werden. Dieses Beispiel ist jedoch absichtlich klein genug und vereinfacht, um Ihnen den Einstieg zu erleichtern und sich auf die Kernfunktionen zu konzentrieren. Wenn Sie dem Tutorial folgen, sollten Sie in der Lage sein, eine Arbeitsumgebung für Ihre Scala-Anwendung auf Ihrem Computer zu erhalten, ohne von einer Vielzahl von Details verwirrt zu werden und sich in der Komplexität zu verlieren.
- Entwicklung für die Cloud in der Cloud: BigData-Entwicklung mit Docker in AWS
- K8s/Kubernetes: AWS vs. GCP vs. Azure
- Ein Kubernetes-Service-Mesh-Vergleich
