Scala Microservices auf Kubernetes deployen (Hands-On)
Die ganze Welt spricht über Docker, Kubernetes (k8s) und Microservices in der Cloud. Unabhängig vom Anbieter der Cloud Infrastruktur, lässt sich Kubernetes heute fast überall problemlos betreiben.
In diesem Blogbeitrag wollen wir eine Hello World Scala Application auf Basis von akka-http in einen Docker Container verpacken, ihn automatisch mithilfe einer Continuous Deployment Pipeline builden lassen und ihn abschließend mit den reactive-cli Tools von Lightbend auf ein Kubernetes Cluster deployen.
Übersicht:
- Unseren Sourcecode verwalten wir in github. Das Beispielprojekt findet ihr unter https://github.com/innFactory/akka-http-kubernetes-101
- Der automatische Build, die Tests und das Deployment auf unser Kubernetes Cluster übernimmt Circle CI für uns.
- Kubernetes wird von der Google Cloud in der Google Kubernetes Engine bereit gestellt.
Hello World Backend mit akka-http in Scala
Das Demoprojekt ist unter https://github.com/innFactory/akka-http-kubernetes-101 veröffentlicht.
Mithilfe von akka-http und Scala wird eine REST Schnittstelle zum Grüßen bereit gestellt – Der Greeter Microservice. Dieser liefert auf dem HTTP Rootpfad eine einfaches OK 200 als Antwort zurück. Über den HTTP Endpunkt /greet/:name wird eine Grußbotschaft für einen Namen zurückgeschickt. Die OK Schnittstelle ist nur für den Healthcheck in Kubernetes wichtig. Zusätzlich wurden drei einfache Tests hinzugefügt, die dieses Verhalten im Testlauf überprüfen können. Im Ordner .circleci befinden sich alle notwendigen Dateien, die Circle CI für das Deployment verwendet.
Kubernetes (k8s) Cluster (GKE)
In keiner Public Cloud ist Kubernetes so gut integriert, wie in der Google Cloud. Das ist natürlich nicht zuletzt darauf zurück zu führen, dass Kubernetes von Google entwickelt wurde. Andere Cloudanbieter wie AWS, IBM oder Azure holen zwar schnell auf, allerdings funktioniert die Integration oft nicht so nahtlos wie man es sich wünschen würde und wie man es von Google kennt. Gerade mit Versionsupdates von Master- und Workernodes haben die anderen Hersteller oft noch Probleme. In unserem Beispiel verwenden wir ein einfaches Cluster, das wir mithilfe des gcloud sdks im Terminal erstellen.
Zuerst setzen wir wichtige Parameter der gcloud config. In meinem Fall muss ich lediglich das Projekt wechseln, da die Region und Zone bei mir bereits richtig eingestellt sind.
gcloud config list sollte nun eine Ausgabe erstellen, die wie folgt aussieht:
Als nächstes gilt es ein Kubernetes Cluster über das gcloud SDK zu erstellen. Die meisten Parameter belassen wir in der Standardeinstellung, da dies für unsere Demo vollkommen ausreichend ist. Unser Cluster soll in Frankfurt laufen und es soll in allen Availability Zones (AZs) ein Worker vorhanden sein. Die Knoten sollen vom Typ g1-small sein (Auflistung aller Instanztypen mit gcloud compute machine-types list).
Nach wenigen Minuten ist unser Cluster verfügbar und für unsere Demo einsatzbereit.
Wir können das Cluster jetzt mit kubectl verwenden. Dazu müssen wir allerdings noch die Zugangsdaten mit gcloud container clusters get-credentials demoregionalcluster bereitstellen.
kubectl get nodes sollte uns nun all unsere Knoten anzeigen.
NAME STATUS ROLES AGE VERSION
gke-demoregionalcluster-default-pool-0fed3e4a-xtcs Ready 2m v1.10.9-gke.5
gke-demoregionalcluster-default-pool-4130f6c1-d00w Ready 2m v1.10.9-gke.5
gke-demoregionalcluster-default-pool-c3c955ab-bqfz Ready 2m v1.10.9-gke.5
Circle CI Pipeline erstellen
Viele Unternehmen betreiben heute einen eigenen Jenkins Server, um ihre Softwarebuilds zu automatisieren. Dagegen spricht nichts, allerdings möchte man im Grunde keinen Aufwand beim Betrieb der Pipelinesoftware haben. Auch die Syntax eines JENKINSFILEs könnte schöner sein. Sucht man im Internet nach SaaS Alternativen findet man schnell Circle CI, Travis oder auch Produkte der großen Cloud Anbieter. Für unser Beispiel verwenden wir, wie auch bei all unseren innFactory Projekten, Circle CI. Für unser Beispiel benötigt man keinen bezahlten Account, denn man erhält bei der Registrierung einen umfangreichen Account mit 1000 Buildminuten pro Monat. Für die Demo reicht dies in jedem Fall aus.
Nach der Anmeldung befindet ihr euch auf dem Circle CI Dashboard. Dort muss zuerst einmal das github Projekt mit dem Scala/akka Backend hinzugefügt werden. Dazu wählt man im linken Menü „Add Projects“ und dann das Projekt auf github. Nach einem Klick auf set-up Project und dann wiederum auf Start building beginnt der erste durchlauf der Pipeline.
Im Scala Demoprojekt auf github befindet sich eine Circle CI Beschreibung für einen CI Workflow (.circleci/config.yml). Dieser Workflow führt parallel alle Tests aus und erstellt gleichzeitig einen Docker Container, der wiederum im Anschluss in einem privaten Google Container Repository gespeichert wird. Nach Beendigung beider Aufgaben wird der Container mithilfe der Reactive Plattform Tools auf das oben erstellte Kubernetes Cluster deployt. Für das Beispiel wird die reactive-cli von Lightbend verwendet. In produktiven Szenarien empfiehlt es sich, das Kubefile generieren zu lassen und dieses mit in das Code Repository einzuchecken. Da für die Jobs im Workflow immer ein Docker Image von innFactory verwendet wird, ist das gesamte Tooling zur Buildzeit immer voll verfügbar (Scala, sbt, reactive-cli).
Damit der Build und somit auch der Workflow funktioniert müssen noch Variablen für die Google Cloud gesetzt werden. Dazu können „Environment Variables“ in den Circle CI Projekteinstellungen erstellt werden.
Die benötigten Variablen, die der Workflow des Scala Demoprojekt verwendet sind:
- GCLOUD_SERVICE_KEY
- GOOGLE_PROJECT_ID
- GOOGLE_COMPUTE_ZONE
- GOOGLE_CLUSTER_NAME
Abgesehen von der ersten Variable sind alle Werte bereits aus der Erstellung des Kubernetes Clusters bekannt. Für den GCLOUD_SERVICE_KEY müsst ihr in der Google Cloud einen Service Account anlegen, der die Berechtigung hat Kubernetes zu verwalten und auch Images in das Container Repository pushen darf. Dieser Service Account sollte von den Berechtigungen möglichst eingeschränkt sein. Für unser Beispiel vergeben wir allerdings Administratorenzugriffe auf die jeweiligen Dienste. Erstellt zum Schluss einen Schlüssel im JSON Format und hinterlegt diesen als Variable GCLOUD_SERVICE_KEY.
Green, Up & Running
Nachdem alle Einzelteile richtig konfiguriert sind, kann der Workflow neu gestartet werden.
Wenn ihr einen kostenfreien Account bei Circle CI habt, laufen die Workflows nicht parallel ab, letztendlich sollte das Ergebnis jedoch am Ende so aussehen, dass ihr in Kubernetes euer Deployment wiederfindet.
kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
akka-http-kubernetes-101-v1-0 3 3 3 3 1m
Wir können das Cluster jetzt mit kubectl verwenden. Dazu müssen wir allerdings noch die Zugangsdaten mit gcloud container clusters get-credentials demoregionalcluster bereitstellen.
kubectl get nodes sollte uns nun all unsere Knoten anzeigen.
NAME STATUS ROLES AGE VERSION
gke-demoregionalcluster-default-pool-0fed3e4a-xtcs Ready 2m v1.10.9-gke.5
gke-demoregionalcluster-default-pool-4130f6c1-d00w Ready 2m v1.10.9-gke.5
gke-demoregionalcluster-default-pool-c3c955ab-bqfz Ready 2m v1.10.9-gke.5
Circle CI Pipeline erstellen
Viele Unternehmen betreiben heute einen eigenen Jenkins Server, um ihre Softwarebuilds zu automatisieren. Dagegen spricht nichts, allerdings möchte man im Grunde keinen Aufwand beim Betrieb der Pipelinesoftware haben. Auch die Syntax eines JENKINSFILEs könnte schöner sein. Sucht man im Internet nach SaaS Alternativen findet man schnell Circle CI, Travis oder auch Produkte der großen Cloud Anbieter. Für unser Beispiel verwenden wir, wie auch bei all unseren innFactory Projekten, Circle CI. Für unser Beispiel benötigt man keinen bezahlten Account, denn man erhält bei der Registrierung einen umfangreichen Account mit 1000 Buildminuten pro Monat. Für die Demo reicht dies in jedem Fall aus.
Nach der Anmeldung befindet ihr euch auf dem Circle CI Dashboard. Dort muss zuerst einmal das github Projekt mit dem Scala/akka Backend hinzugefügt werden. Dazu wählt man im linken Menü „Add Projects“ und dann das Projekt auf github. Nach einem Klick auf set-up Project und dann wiederum auf Start building beginnt der erste durchlauf der Pipeline.
Im Scala Demoprojekt auf github befindet sich eine Circle CI Beschreibung für einen CI Workflow (.circleci/config.yml). Dieser Workflow führt parallel alle Tests aus und erstellt gleichzeitig einen Docker Container, der wiederum im Anschluss in einem privaten Google Container Repository gespeichert wird. Nach Beendigung beider Aufgaben wird der Container mithilfe der Reactive Plattform Tools auf das oben erstellte Kubernetes Cluster deployt. Für das Beispiel wird die reactive-cli von Lightbend verwendet. In produktiven Szenarien empfiehlt es sich, das Kubefile generieren zu lassen und dieses mit in das Code Repository einzuchecken. Da für die Jobs im Workflow immer ein Docker Image von innFactory verwendet wird, ist das gesamte Tooling zur Buildzeit immer voll verfügbar (Scala, sbt, reactive-cli).
Damit der Build und somit auch der Workflow funktioniert müssen noch Variablen für die Google Cloud gesetzt werden. Dazu können „Environment Variables“ in den Circle CI Projekteinstellungen erstellt werden.
Die benötigten Variablen, die der Workflow des Scala Demoprojekt verwendet sind:
- GCLOUD_SERVICE_KEY
- GOOGLE_PROJECT_ID
- GOOGLE_COMPUTE_ZONE
- GOOGLE_CLUSTER_NAME
Abgesehen von der ersten Variable sind alle Werte bereits aus der Erstellung des Kubernetes Clusters bekannt. Für den GCLOUD_SERVICE_KEY müsst ihr in der Google Cloud einen Service Account anlegen, der die Berechtigung hat Kubernetes zu verwalten und auch Images in das Container Repository pushen darf. Dieser Service Account sollte von den Berechtigungen möglichst eingeschränkt sein. Für unser Beispiel vergeben wir allerdings Administratorenzugriffe auf die jeweiligen Dienste. Erstellt zum Schluss einen Schlüssel im JSON Format und hinterlegt diesen als Variable GCLOUD_SERVICE_KEY.
Green, Up & Running
Nachdem alle Einzelteile richtig konfiguriert sind, kann der Workflow neu gestartet werden.
Wenn ihr einen kostenfreien Account bei Circle CI habt, laufen die Workflows nicht parallel ab, letztendlich sollte das Ergebnis jedoch am Ende so aussehen, dass ihr in Kubernetes euer Deployment wiederfindet.
kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE akka-http-kubernetes-101-v1-0 3 3 3 3 1m