In der Java-Welt ist das Integrations-Framework Apache Camel bereits ein alter Hase. Die vielfältigen Adapterkomponenten lassen kaum Wünsche offen, wenn es darum geht ein (Fremd-)System oder eine bestimmte Schnittstelle zu integrieren. Für den Einsatz in Serverless-Umgebungen auf einem Kubernetes-Cluster gibt es nun eine native Integration, die die Entwicklung von Camel-Routen vereinfachen soll.

Dieser Artikel soll einen ersten Einblick in das Camel-Unterprojekt Camel K geben.

Was ist Camel K ?

Begriffsdefinition

Camel K (gelegentlich auch Camel-K oder camel-k geschrieben) ist ein leichtgewichtiges Integrations-Framework auf Basis von Apache Camel, dass nativ auf Kubernetes läuft und für Serverless und Microservice-Architekturen entwickelt wurde.

Aus Entwickler-Sicht wird nur die eigentliche Camel-Route erstellt und diese z.B. als Groovy, Java etc. Datei deployt. Aktuell (Stand: 18.03.2021) werden 7 unterschiedliche Sprachen unterstützt. Dazu zählen:

  • Java
  • JShell
  • XML
  • YAML
  • Groovy
  • Kotlin
  • JavaScript

Installation von Camel K

Die Installation von Camel K ist in der camel-k Dokumentation beschrieben. Im folgenden soll die Installation auf Minikube erläutert werden.

Installation am Beispiel von Minikube

Nach dem Download kann man Minikube auf VirtualBox wie folgt starten:

minikube start --driver virtualbox

Danach muss noch das Registry-Addon aktiviert werden:

minikube addons enable registry

Nachdem Minikube nun gestartet ist, kümmern wir uns um die Installation der kamel CLI. Damit wird dann auch Camel K in Kubernetes installiert. Nachdem die kamel CLI eingerichtet ist, können wir mit kamel install den camel-k-operator installieren. Dieser kümmert sich um die eigentliche Ausführung der Camel-Routen in Kubernetes.

Mit den folgenden Befehlen legen wir einen neuen Namespace (camel-basic) für unser nachfolgendes Beispiel an und installieren darin Camel K:

kubectl create namespace camel-basic
kubectl config set-context --current --namespace=camel-basic
kamel install

 

TIP Der Camel-K-Operator wird nur für den jeweils gewählten Kubernetes-Namespace installiert. Wenn ein neuer Namespace angelegt wird, dann muss der kamel install-Befehl erneut ausgeführt werden.
Die Installation in einem Kubernetes Cluster wird über den Befehl kamel install --cluster-setup durchgeführt. In dem Fall wird die Installation über eine Custom Resource Definitions (CRD) im Cluster eingerichtet und benötigt entsprechend Admin-Rechte.

Der erste Start kann etwas dauern. Evtl. fehlt auch noch ein Integration-Kit. Das kann man mit dem Befehl

kamel kit create default

nachholen. Der Name default ist hier willkürlich gewählt.

Hello-World-Beispiel

Nun können wir unsere erste Camel-Route in Kubernetes starten. Ein einfaches HelloWorld-Beispiel kann z.B. so aussehen:

from('timer:tick?period=3000')
  .setBody().constant('Hello world from Camel K')
  .to('log:info')

Die Bespiel-Route kann mit dem Befehl kamel init hello-world.groovy angelegt werden. Danach kann man mit dem Befehl

kamel run hello-world.groovy

die Camel-Route in Kubernetes deployen. Dabei werden folgende Aufgaben vom Kubernetes-Cluster automatisch übernommen:

  • Auflösung aller benötigten Dependencies
  • Erstellung der benötigten Deployment Konfiguration
  • Start des jeweiligen Pods für die Ausführung der Camel-Route

Die benötigten Dependencies werden anhand der verwendeten Adapter in der Camel-Route automatisch ermittelt.

Mit dem Befehl kamel get können alle aktuell ausgeführten Integrations abgefragt werden:

$ kamel get
NAME            PHASE   KIT
helloworld      Running kit-c15hl5gfc8h01ii2rung

Verwendung des DEV-Modes

Gerade am Anfang der Entwicklung ist es von Vorteil ein schnelles Feedback über mögliche Fehler beim Start der Anwendung zu bekommen. Dazu bietet Camel K den sog. DEV-Mode. Die Camel-Integration wird dazu mit dem Parameter --dev gestartet.

Beispiel: Basic.java

import org.apache.camel.builder.RouteBuilder;

public class Basic extends RouteBuilder {

    @Override
    public void configure() throws Exception {

      from("timer:java?period=1000")
        .setHeader("example")
          .constant("java")
        .setBody()
          .simple("Hello World! Camel K route written in ${header.example}.")
        .to("log:info");
  }
}

 

Das obige Beispiel lässt sich mit kamel run Basic.java --dev im DEV-Mode starten. Während man auf der Konsole die Log-Ausgabe sieht kann man den Source-Code abändern (DEV-Loop). Er wird dann automatisch neu deployt. Der Name der Integration wird automatisch aus dem Klassennamen abgeleitet und in ein „lower-case“ umgewandelt. Durch Verwendung des dev-Modes bekommt man direkt Feedback, ob alle Abhängigkeiten korrekt aufgelöst werden konnten.

Logs abrufen

Ohne den Start im DEV-Mode kehrt der Command-Prompt direkt zurück und man kann sich die Logs des ausgeführten Pods anschauen:

kamel logs basic 
[1] 2021-03-18 09:29:27,895 INFO  [info] (Camel (camel-1) thread #0 - timer://java) Exchange[ExchangePattern: InOnly, BodyType: String, Body: Hello World! Camel K route written in java.]

Mit kamel delete basic kann man die Integration wieder löschen.

Architektur

Programmiermodell

Das Programmiermodell zielt auf die einfache Definition von Camel-Routen und deren Betrieb als Serverless-Funktionen (aka Functions) ab. Dabei dient Kubernetes/OpenShift als Laufzeitumgebung dieser Funktionen, die in diesem Fall durch Camel-Routen repräsentiert werden.

Die Entwicklung der eigentlichen Camel-Routen steht im Vordergrund der Entwicklung. Details rund um Build- und Deploymentmanagement verlagert sich in die Laufzeitumgebung.

Integrations

Camel K Anwendungen werden Integrations genannt. Diese Integrations haben einen Lifecycle. Sie können z.B. gestartet und wieder gelöscht werden. Alle Aufgaben werden über das CLI-Tool kamel erledigt.

Components

Components sind die Camel-Adapter, die in Camel-Routen verwendet werden. Sie können entweder programmatisch in der Route oder mit Hilfe von Properties konfiguriert werden.

Konfiguration

Properties von Integrationen können in Properties-Dateien oder in ConfigMaps bzw. Secrets ausgelagert werden. Der jeweilige Wert wird dann in der Camel-Route über eine Expression ermittelt.

Beispiel: props.groovy

from('timer:props?period=1000').log('{{my.message}}')

Eine entsprechende ConfigMap für den Wert von my.message könnte dann so aussehen:

my-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  application.properties: |
    my.message=Hello World
    logging.level.org.apache.camel=DEBUG

Die ConfigMap muss dann erst in Kubernetes angelegt werden und kann anschließend beim Start der Integration referenziert werden.

kubectl apply -f my-config.yaml
kamel run --configmap=my-config props.groovy

Plattform Konzepte

Das folgende Diagramm gibt einen groben Überlick über die Architektur:

Camel K High Level Architektur

Die wesentlichen Plattform-Elemente setzen sich aus folgenden Komponenten zusammen:

  • Operator
  • Runtime
  • Traits

Operator

Die Camel-K-Integration in Kubernetes erfolgt über einen Kubernetes-Operator. Operators sind Erweiterungen in Kubernetes, die sich auf Custom Resources als Extension der Kubernetes API beziehen.

Durch den Aufruf von kamel install wird der camel-k-operator in dem gewählen Kubernetes-Namespace installiert. Mit dieser Installation können Integrations im Kubernetes-Namespace gestartet werden.

Runtime

Die Runtime kümmmert sich um die eigentliche Ausführung der Integrations in Kubernetes. Die Default-Runtime ist Quarkus.

Traits

Über Traits werden „High Level Features“ in Camel K realisiert. Im Wesentlichen ist damit die Integration von Third-Party-Frameworks gemeint, wie z.B. Knative, OpenAPI, Prometheus etc, oder Basis-Funktionen der Laufzeitumgebung, z.B. Routen und Services in Kubernetes bzw. OpenShift.

Traits haben Profile und Eigentschaften. Profile besagen auf welcher Laufzeitumgebung der jeweilige Trait anwendbar ist, z.B. Kubernetes oder OpenShift.

Eigenschaften eines Traits werden über Properties konfiguriert, mit der weitere individuelle Einstellungen möglich sind. Alle Traits haben beispielweise die Eigenschaft enabled. Das Property folgt dem Namensschema TRAIT_NAME.enabled=true/false, also z.B. istio.enabled=true. Einige Traits sind standardmäßig aktiviert. Beispielsweise ist der Dependency Trait ein Platform Trait, der standardmäßig auf den Plattformen Kubernetes, Knative und OpenShift aktiviert ist.

Aktuell gibt es 31 Traits (Stand: 18.03.2021).

Abgrenzung zu Apache Camel

High-Level-Abstraktionen mit Kamelets

Kamelets (Kamel route snippets) basieren auf einem neuem Konzept von Adaptern, um auf externe Systeme zuzugreifen. Alle technischen Details werden dabei in einem Kamelet gekapselt und ermöglichen dadurch eine relativ einfache Verwendung in den Camel Routen. Alle Low-Level-Details werden so in wiederverwendbare Komponenten verpackt.

Ein Kamelet besteht aus einer Source und einer Sink, also der Definition einer Quelle und eines Ziels von einem externen System.

Verwendung von Kamelets in Camel Routen

Kamelets können wir normale Camel-Adapter in Routen verwendet werden. Dabei wird der kamelet-Prefix als Adapter-Name verwendet. Beispiel:

from("kamelet:telegram-text-source?botToken=XXXXYYYY")
   .to("kamelet:my-company-log-sink/mynamedconfig")

Nach dem Prefix folgt der Name des Kamelets mit anschließenden Konfigurationsparametern.

Aufbau eines Kamelets

Ein Kamelet ist technisch gesehen eine Kubernetes Ressource. In ihrer Konfiguration im YAML-Format ist auch ein Routen-Template enthalten über die grundlegende Funktionsweise des Kamelets. Gekennzeichnet sind die Konfigurationsdateien durch das folgende Namensschema: yourkamelet.kamelet.yaml.

Über optionale Kamelet Bindings kann eine „Brücke“ zu anderen Integrationstechnologien, wie z.B. Knative hergestellt werden.

Weitere Details finden sich im Kamelets User Guide.

Testing

Tests mit YAKS

In der offiziellen Dokumentation findet man keinen Hinweis darauf, wie man Camel K Integrations testen kann. Es ist aber zu erwarten, dass es eine Unterstützung für das Testing geben wird.

Laut dem Issue-Tracker von Camel K in GitHub wurde bereits danach gefragt. Voraussichtlich wird es eine offizielle Unterstützung auf Basis von YAKS geben, das wiederum auf dem Citrus-Framework basiert und eine Erweiterung für Cloud Native BDD Testing auf der Kubernetes-Plattform darstellt.

YAKS Tests werden als BBD-Features auf Basis der Gherkin-Syntax geschrieben und geben eine definierte Struktur vor, wie sie auch in Cucumber-Tests verwendet wird.

Wie Camel K selbst muss vor der ersten Testausführung der YAKS Operator installiert werden. Das erfolgt, wie auch die spätere Testausführung, über die YAKS CLI.

Sobald die YAKS CLI installiert ist, kann man den Operator mittels

yaks install

installieren. Anschließend können wir z.B. einen einfachen HelloWorld-Test ausführen:

helloworld.feature

Feature: Hello

  Scenario: Print hello message
    Given print 'Hello from YAKS!'

Die erfolgreiche Installation kann mittels kubectl get customresourcedefinitions -l app=yaks überprüft werden.

Mit

yaks test helloworld.feature

können wir nun unseren Test ausführen. Der Befehl erstellt als Ergebnis ein _output-Verzeichnis mit den Testergebnisssen (helloworld.json und junit-reports.xml).

Die Tests selbst werden als ConfigMap im jeweiligen Namespace in Kubernetes gespeichert.

CI/CD-Pipelines mit Tekton

CI/CD-Pipelines werden in Kubernetes über Tekton realisiert. Über die Tekton CLI kann man einzelne Tasks auf der Konsole starten.

Tasks sind einzelne Steps in einer Tekton-Pipeline. Dies ist ein einfaches HelloWorld-Beispiel:

task-hello.yaml

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: hello
spec:
  steps:
    - name: hello
      image: ubuntu
      command:
        - echo
      args:
        - "Hello World!"

Mit dem Befehl kubectl apply -f task-hello.yaml wird der Task angelegt und mit tkn task start hello ausgeführt. Das Ergebnis kann man sich mit tkn taskrun logs --last -f anzeigen lassen.

$ tkn taskrun logs --last -f
[hello] Hello World!

Tekton Dashboard

Es gibt auch ein Tekton Dashboard, in dem man sich die Pipelines (ähnlich zu Jenkins) anzeigen lassen kann.

Mit folgenden Befehlen wird das Dashboard in Minikube installiert und über einen Proxy lokal zugreifbar gemacht:

kubectl apply --filename https://github.com/tektoncd/dashboard/releases/latest/download/tekton-dashboard-release.yaml
kubectl proxy --port=8080

Anschließend kann das Dashboard im Browser unter http://localhost:8080/api/v1/namespaces/tekton-pipelines/services/tekton-dashboard:http/proxy aufgerufen werden. Unter Tasks bzw. TaskRuns kann man sich den Task anzeigen lassen.

Tekton Dashboard

Über einen Camel K Integration Task für Tekton kann Camel K direkt in Tekton Pipelines verwendet werden.

Unterschiede zwischen Camel und Camel K

Wenn eine Serverless-Architektur als Zielplattformumgebung gewünscht ist, so muss an dieser Stelle auf die umfrangreichen Integrationsmöglichkeiten von Apache Camel nicht verzichtet werden. Im Vergleich zu Apache Camel liegt hier allerdings der Fokus auf der eigentlichen Camel-Route mit deren Integration in die Kubernetes-Laufzeitumgebung sowie der Einbindung und Nutzung entsprechender Serverless- und Microservices-Frameworks, wie z.B. Knative und Quarkus.

Die klassischen Camel-Anwendungen werden üblicherweise als Binärartefakt deployt. Beispielsweise kann man eine Spring-Boot-Anwendung mit Camel aufsetzen und das FAT-JAR-Artefakt direkt starten oder in einem Docker-Container gekapselt betreiben. Das „Drumherum“ passiert also lokal auf dem Entwicker-Rechner (oder entsprechend in der CI/CD-System). Im Vergleich dazu beinhalten die Camel K Anwendungen „einfach“ nur die Camel-Routen-Definitionen als einzelne Datei im jeweils gewünschen Format (z.B. Groovy, Java, XML etc.“‹).

Im Endeffekt verlagern sich die Build- und Deployment-Aufgaben eher in Richtung Plattform und werden von dieser automatisch übernommen.

Im Folgenden sollen die Vor- und Nachteile von Camel K kurz zusammengefasst werden:

Vorteile von Camel K

  • Source-Code auf das Nötigste (aka Camel-Route, Properties etc.) beschränkt
  • automatische Ermittlung der Abhängigkeiten
  • automatisches Build- und Deployment nach Kubernetes mit kamel run...
  • automatische Anlage von Services, Routen und ConfigMaps etc.
  • kein separates Dockerfile oder Source-2-Image(S2I)-Build notwendig
  • DEV-Mode propagiert automatisch alle Änderungen auch in den laufenden Pod
  • Servlerless-Ansatz (in Verbindung mit Knative oder OpenShift Serverless)
    • kurze Startzeiten
    • Ressourcen werden geschont, wenn sie nicht benötigt werden
    • geringer Speicherverbrauch
    • Ausführung bei Bedarf

Nachteile von Camel K

  • Verlagerung der Komplexität in die Laufzeitumgebung
    • höhere Abhängigkeit zur Laufzeitumgebung während der Entwicklung
    • Fehlersuche kann evtl. recht mühsam werden
    • Konfigurationsdateien sind ggf. „verstreut“ im System (Abbildung von Properties in ConfigMaps)
  • (noch) relativ neu
    • Einige Teile von Camel K oder Knative befinden sich noch im Alpha-Stadium
    • Dokumentation (noch) unvollständig
  • setzt grundsätzlich Kubernetes/OpenShift als Laufzeitumgebung voraus

Observability

Monitoring

Das Camel K Monitoring wird über eine Integration mit Prometheus unterstützt. Dafür gibt es einen speziellen Prometheus Operator. Das Projekt befindet sich allerdings noch im Beta-Status (Stand: 16.03.2021).

Der Prometheus Operator wird analog wie der camel k operator als Ressource in einem Kubernetes-Namespace installiert. Alle Applikationen, die in dem Namespace laufen, in der auch der Prometheus Operator läuft, können damit überwacht werden.

Beim der Installation des camel k operator kann das Monitoring auch direkt für alle Integrationen aktiviert werden:

kamel install --monitoring=true --monitoring-port=8888

Metriken

Mit dem Prometheus Trait wird der Prometheus-kompatible Endpunkt konfiguriert.

Mittels der Camel Quarkus MicroProfile Metrik Extension werden die Metriken im OpenMetric-Format bereitgestellt. Neben JVM und OS-bezogenen Metriken gibt es ein paar Camel K spezifische Metriken. Dazu zählen z.B.

  • Anzahl an Routen
  • Anzahl an ausgeführten Routen
  • gesamte Anzahl an erfolgreich ausgeführten Exchanges
  • gesamte Anzahl an fehlerhaft ausgeführten Exchanges

Weitere Details siehe Camel K Integration Monitoring.

Logging

Camel K verwendet Log4j 2 als Logging-Framework. Der Logging Level kann über Properties angepasst werden. Der folgende Befehlt setzt z.B. das Log-Level auf DEBUG:

kamel run --property logging.level.org.apache.camel=DEBUG helloworld.groovy

Service Tracing

Es gibt einen Tracing Trait, der Tracing-Informationen an einen OpenTracing-kompatiblen Collector schicken kann und auch Jaeger unterstützt. Der Tracing Trait muss separat aktiviert und konfiguriert werden, z.B.

kamel run --trait tracing.enabled=true --trait tracing.auto=true helloworld.groovy

Tooling

Extensions für Visual Studio Code

Für Visual Studio Code gibt es das Tooling for Apache Camel K by Red Hat. Damit kann man neue Camel-K-Dateien anlegen und auch deployen bzw. löschen lassen.

In einem Explorer-Fenster werden die Camel-K-Integrations angezeigt.

Visual Studio Code Plugin für Camel K

Fazit

Mit Camel K wurde das beliebte Apache Camel Framework auf die Kubernetes Plattform portiert und fungiert damit als leichtgewichtige ESB-Alternative, das die Vorzüge dieser Plattform versucht bestmöglich auszunutzen. Es positioniert sich als Integrations-Framework für Serverless- und Microservices-Architekturen und integriert dabei Frameworks, die die gleiche Laufzeitumgebung zum Ziel haben (z.B. Quarkus, Knative etc.).

Wer sich eine Serverless-Architektur zunutze machen will, der sollte einen Blick auf Camel K werfen. Durch den geringen Ressourcen-Footprint, den Serverless-Anwendungen mit sich bringen, lassen sich durch den Einsatz gerade in Cloud-Umgebungen Kosten sparen und in On-Premises-Umgebungen zumindest Ressourcen effizienter nutzen.

Da das Framework noch relativ jung ist und viele Artefakte noch im Alpha-Status sind, sollte ein Einsatz in Produktivumgebungen noch mit Bedacht gewählt werden. Es ist aber zu erwarten, dass sich dieses Risiko im Laufe der Zeit minimieren wird. Zumindest erfreut sich das Projekt einer aktiven Community.

Da Camel K auf Kubernetes aufsetzt, sollte klar werden, dass ein lauffähiges Kubernetes-Cluster eine notwendige Voraussetzung für den erfolgreichen Einsatz ist. Das ist kein leichtes Unterfangen; hier sollte man sich im Klaren sein, dass der produktive Betrieb eines Kubernetes-Clusters eine durchaus technische Herausforderung sein kann. Dafür muss das benötigte Wissen im Unternehmen vorhanden sein. Selbst wenn man bei dem Betrieb auf einen Cloud-Provider ausweicht (z.B. AWS EKS oder Azure AKS), sollte der Betrieb eines Kubernetes-Clusters nicht unterschätzt werden.

Zwar vereinfacht sich die lokale Entwicklung durch Fokussierung auf die reinen Camel-Routen, allerdings verschiebt sich dadurch auch die Komplexität im Hinblick auf die Konfigurationseinstellungen in Richtung des Kubernetes-Clusters selbst. Hier sind einige Konfigurationen vorzunehmen, um alle benötigten Voraussetzungen in Kubernetes zu erfüllen (z.B. Installation und Konfiguration des Camel K Operators, Aktivierung von Traits, Properties etc.). Im Testing-Bereich gibt es erste Ansätze für Integration-Testing mit Citrus und YAKS. Für Unit-Tests muss allerdings auf die „klassische“ Vorgehensweise zurückgegriffen werden.

Alles in Allem hat Camel K das Potenzial für eine leichtgewichtige ESB-Alternative. Es bleibt abzuwarten, wie sich das Framework weiterentwickelt und auf welche Akzeptanz es in Zukunft in der Praxis stoßen wird.

Links:

 

Alle Beiträge von Michael Stähler

Solution Architect, AWS Certified Solution Architect - Professional

Schreibe einen Kommentar