Neuigkeiten von trion.
Immer gut informiert.

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:

Kubeless Resourcen im Kubernetes Dashboard

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.

Context Klasse
public class Context
{
	String functionName;
	String timeout;
	String runtime;
	String memoryLimit;
...
Event Klasse
public class Event
{
	String Data;
	String EventID;
	String EventType;
	String EventTime;
	String EventNamespace;
...

Als Beispiel wird die folgende Funktion verwendet:

Kubeless Funktion in Java
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:

POM für Kubeless mit Java
<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.

Feedback oder Fragen zu einem Artikel - per Twitter @triondevelop oder E-Mail freuen wir uns auf eine Kontaktaufnahme!

Los geht's!

Bitte teilen Sie uns mit, wie wir Sie am besten erreichen können.