Kubernetes und Java Serverless - Function as a Service
Der Trend weg von großen, schwerfälligen Applikationsservern hin zu Microservices und Containern wird durch die Cloud als Ablaufumgebung stark beschleunigt. Konsequent weitergedacht erhält man noch kleinere Dienste, Nanoservices, die lediglich einzelne Funktionen umsetzen. Als minimale Deploymenteinheit lässt sich darüber eine feingranulare Skalierung erzielen, und durch verringerten Overhead eine kosteneffiziente Nutzung der Infrastruktur realisieren. Vorreiter war Amazon mit Lambda, doch auch andere Cloud Anbieter zogen schnell nach, und bieten Function-as-a-Service (FaaS) oder "serverless" Umgebungen an.
Kubernetes als De-facto-Standard für containerbasierte Cloudinfrastruktur bietet von Haus aus zwar kein vergleichbares Modell an, jedoch gibt es mit Oracle Fn, Kubeless und Open Whisk zahlreiche Projekte, die FaaS als OpenSource Plattform für den Einsatz in eigener Cloudinfrastruktur oder auch öffentlichen Kubernetes Cloud-Runtimes ermöglichen wollen.
Im folgenden wird ein kurzer Blick auf Kubeless in Kombination mit Java geworfen. Ausschlaggebend für diese Auswahl war ein relativ unkompliziertes Setup, wodurch die Hemmschwelle für Experimente verringert wird.
Das Kubeless Projekt ist OpenSource und findet sich bei GitHub: https://github.com/kubeless/kubeless
Installation von Kubeless
Kubeless verwendet eine Custom Resource Definition in Kubernetes. Dadurch können die Funktionen durch entsprechende Kubernetes Controller überwacht und verwaltet werden. Nachdem - beispielsweise mit minikube - ein Kubernetes Cluster zur Verfügung steht, kann Kubeless folgendermassen installiert werden:
#Aktuelle Version von Kubeless ermitteln
$ export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kubeless/releases/latest | grep tag_name | cut -d '"' -f 4)
#Kubernetes Namespace für Kubeless anlegen
$ kubectl create ns kubeless
#Installation von Kubeless Resourcen
$ kubectl create -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml
deployment "kubeless-controller-manager" created
serviceaccount "controller-acct" created
clusterrole "kubeless-controller-deployer" created
clusterrolebinding "kubeless-controller-deployer" created
customresourcedefinition "functions.kubeless.io" created
customresourcedefinition "httptriggers.kubeless.io" created
customresourcedefinition "cronjobtriggers.kubeless.io" created
configmap "kubeless-config" created
Wer einen lokalen Kubernetes Cluster mit minikube verwendet, muss RBAC aktiviert haben, oder das non-rbac Kubeless Deployment verwenden. Auch etwas mehr RAM schadet nicht:
$ minikube start --memory 4096 --cpus 4 --extra-config=apiserver.authorization-mode=RBAC
Um sich von der korrekten Funktion zu überzeugen, können die zugehörigen Kubernetes Resourcen geprüft werden:
$ kubectl get pods -n kubeless
$ kubectl get deployment -n kubeless
$ kubectl get customresourcedefinition
Im Kubernetes Dashboard können die zu dem kubeless-Namespace gehörenden Resourcen inspiziert werden:
Zur Verwaltung der Kubeless Funktionen wird am besten das kubeless
-CLI Programm verwendet.
Die Installation unter Linux erfolgt als einzelnes Binary:
$ export OS=$(uname -s| tr '[:upper:]' '[:lower:]')
$ curl -OL https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless_$OS-amd64.zip && \
unzip kubeless_$OS-amd64.zip && \
sudo mv bundles/kubeless_$OS-amd64/kubeless /usr/local/bin/
Die Installation ist nun soweit abgeschlossen, und es kann eine erste Funktion erstellt und deployt werden.
Kubeless mit Java
Aktuell ist Kubeless noch ein recht junges Projekt, ebenfalls ist der Java Support entsprechend frisch.
Aktuell werden lediglich Java Funktionen unterstützt, die im Package io.kubeless
liegen und als Parameter einen Event
sowie Context
erhalten und als Ergebnis einen String liefern.
Für Abhängigkeiten und Build kann Maven verwendet werden - die Kubeless Abhängigkeiten befinden sich aktuell nicht in Maven-Central, jedoch funktioniert ein Build über das kubeless
-CLI.
public class Context
{
String functionName;
String timeout;
String runtime;
String memoryLimit;
...
public class Event
{
String Data;
String EventID;
String EventType;
String EventTime;
String EventNamespace;
...
Als Beispiel wird die folgende Funktion verwendet:
package io.kubeless;
import io.kubeless.Event;
import io.kubeless.Context;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Sample
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public String sayHello(io.kubeless.Event event, io.kubeless.Context context)
{
System.out.println(event.EventID + ": " + event.Data);
LocalDateTime now = LocalDateTime.now();
String time = now.format(formatter);
return "Hello world! Current local time is: " + time;
}
}
Das Deployment erfolgt über das kubeless
-CLI:
$ kubeless function deploy java-sample --runtime java1.8 --handler Sample.sayHello --from-file Sample.java
INFO[0000] Deploying function...
INFO[0000] Function java-sample submitted for deployment
INFO[0000] Check the deployment status executing 'kubeless function ls java-sample'
Während Build und Deployment läuft, kann der Status ebenfalls mit kubeless
geprüft werden:
$ kubeless function ls java-sample
NAME NAMESPACE HANDLER RUNTIME DEPENDENCIES STATUS
java-sample default Sample.sayHello java1.8 0/1 NOT READY
Nach einer Weile steht die Funktion zur Verfügung:
$ kubeless function ls java-sample
NAME NAMESPACE HANDLER RUNTIME DEPENDENCIES STATUS
java-sample default Sample.sayHello java1.8 1/1 READY
Falls ein Maven Build gewünscht ist, muss die POM ein besonderes Format aufweisen:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>function</artifactId>
<name>function</name>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>io.kubeless</groupId>
<artifactId>params</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<parent>
<groupId>io.kubeless</groupId>
<artifactId>kubeless</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
</project>
Und das Deployment muss Maven aufrufen:
$ kubeless function deploy java-sample --runtime java1.8 --handler Sample.sayHello --from-file src/main/java/io/kubeless/Sample.java --dependencies pom.xml
Aufruf der Kubeless Funktion
Der Aufruf von Funktionen in Kubeless kann aktuell über drei Wege erfolgen: * Kafka Messages * NATS Messages * HTTP Aufruf
Ohne komplexe weitere Infrastruktur kann ein HTTP Aufruf genutzt werden, um die Funktion zu testen. Kubeless verwendet dabei Kubernetes Ingress Controller um die zu den Funktionen gehörenden Services bereitzustellen.
Verwendet man minikube, so muss Ingress als Addon aktiviert werden:
$ minikube addon enable ingress
ingress was successfully enabled
Die Funktion wird dann als HTTP-Trigger Objekt bereitgestellt:
$ kubeless trigger http create java-sample --function-name java-sample --path java --hostname faas.example.com
INFO[0000] HTTP trigger java-sample created in namespace default successfully!
Ein Aufruf kann dann mittels curl erfolgen:
$ minikube ip
192.168.99.102
$ curl --data '{"Call me": "maybe"}' \
--header "Host: faas.example.com" \
--header "Content-Type:application/json" \
192.168.99.102/java
Hello world! Current local time is: 2018-05-21 14:25:32
Kubeless UI
Kubeless bringt eine eigene Oberfläche mit. Diese kann sehr einfach ebenfalls in Kubernetes eingerichtet werden:
$ kubectl create -f https://raw.githubusercontent.com/kubeless/kubeless-ui/master/k8s.yaml
serviceaccount "ui-acct" created
clusterrole "kubeless-ui" created
clusterrolebinding "kubeless-ui" created
deployment "ui" created
service "ui" created
Bei Verwendung von Minikube erfolgt der Browser Aufruf zum Beispiel so:
$ minikube service -n kubeless ui
Opening kubernetes service kubeless/ui in default browser...
Durch die Weboberfläche lassen sich die Aufrufe der Kubeless-Functions etwas komfortabler durchführen. Außerdem ist darüber auch eine Modifikation der Funktion möglich.
Zu den Themen Kubernetes, Docker und Cloud Architektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.