Die Werkzeugkiste #2: Container und Serverless: Was kann Knative?

Google hatte das Tool Knative im Rahmen der Cloud Next vorgestellt. Es schickt sich an, als plattformagnostisches Tool für Serverless-Anwendungen zu fungieren.

Werkzeuge  –  0 Kommentare
Die Werkzeugkiste #2: Container und Serverless: Was kann Knative?

In der heise-Developer-Serie "Die Werkzeugkiste" stellen Entwickler in regelmäßigen Abständen ihre nützlichsten Werkzeuge, Tools, und Hilfsmittelchen vor. Wie bei der Werkzeugkiste von Handwerkern gilt auch hier: Die Kisten sind meist ziemlich voll – die Auswahl des bevorzugten Werkzeugs für eine Arbeit immer subjektiv. Wenn Sie ihr Lieblings-Tool vermissen oder selber gerne in einem Artikel vorstellen wollen, schreiben Sie doch einfach eine E-Mail an heise Developer.

Mit Knative sollen Entwickler einfacher Serverless-Apps deployen und ausführen können. Die Plattform setzt auf der Containerorchestrierung Kubernetes sowie dem Service-Mesh Istio auf und ist ein Open-Source-Projekt. Der Artikel gibt einen Einblick in Knative und etwaige Anwendungsfälle.

Seine Entwicklung verdankt Knative Herausforderungen der eventgetriebenen Programmierung: Kleinere Aktionen sind, durch ein Event ausgelöst, wiederholt auszuführen. Typisch ist das beispielsweise bei ETL-Prozessen (Extract, Transform, Load), die Daten für die Verarbeitung etwa aus einer öffentlichen Cloud in ein Rechenszentrum laden müssen. Wenn ein Prozess eine Funktion 100.000-mal anstößt, ist es vorteilhaft, wenn sie in einem Container verpackt daherkommt: Der Prozess startet deutlich schneller und bringt die Skalierbarkeit gleich mit.

Bisher war es nicht möglich, Container-Funktionen in Serverless-Umgebungen zu nutzen, da schlicht keine Standards für Public Clouds existierten. Eine Funktion für Microsoft Azure benötigt andere Spezifikationen als eine für Amazon Web Services (AWS) oder die Google Cloud. Knative soll zum Standard für Plattformen werden, der es ermöglicht, Funktionen innerhalb einer öffentlichen Cloud oder beliebig zwischen mehreren Clouds unterschiedlicher Ausprägungen hin und her zu portieren. Dadurch kann ein Prozess flexibel skalieren und beispielsweise die Rechenkapazitäten einer beliebigen Cloud nutzen, wenn das eigene Rechenzentrum nicht ausreicht.

Knative im Überblick

Google hatte das Open-Source-Projekt Knative im Januar 2018 ins Leben gerufen und Ende Juli 2018 offiziell vorgestellt. Unternehmen wie Pivotal, IBM und Red Hat sind ebenfalls involviert.

Die Plattform basiert auf Kubernetes. Das Containerorchestrierungs-Tool hilft Entwicklern beim Deployment, dem Betrieb, der Wartung und der Skalierung von in Container verpackten Microservices. Per Definition der beteiligten Unternehmen erweitert Knative Kubernetes nun um mehrere Komponenten für das Erstellen quellenzentrierter und containerbasierter Serverless-Anwendungen. Zur bewährten Portierbarkeit von Containern kommt also ein Maß Flexibilität hinzu.

Knative soll den Entwicklern einige Vorgänge abnehmen. Dazu gehört beispielsweise die Orchestrierung von Source-to-Container-Workflows, das Management des Traffics während des Deployments oder das automatisierte Skalieren der Workloads. Um welche Art von Workloads es sich handelt, ist bei Knative egal: Entwickler können ihren Workload in Form von Funktionen, Applikationen oder Containern aus den von ihnen bevorzugten Sprachen und Frameworks deployen.

Knative nutzt den gleichen Ansatz wie Kubernetes. Dessen Modell basiert auf Resource Controllers, die die Ressourcen, sprich die Cluster, überwachen, sie ständig mit dem gewünschten Status abgleichen und wenn nötig anpassen. Auf Kelsey Hightower, einer von Googles Kubernetes-Spezialisten, geht folgende Zusammenfassung zurück: "Kubernetes ist eine Plattform, um Plattformen zu bauen. Knative ist eine der Plattformen, die auf Kubernetes aufsetzt und ist ebenfalls dazu geeignet, Plattformen zu entwickeln." Was heißt das konkret?

Serving, Build, Eventing – die Komponenten von Knative

Knative stellt ein Set von Middleware-Komponenten bereit, die zurzeit vor allem drei Bereiche abdecken: Serving, Build und Eventing. Als Basis dafür benötigt es einen Kubernetes-Cluster auf einer entsprechenden Plattform.

Knative Serving definiert einen Satz von Objekten als Kubernetes Custom Resource Definitions (CRD). Sie kontrollieren und legen fest wie sich der Serverless Workload auf dem Cluster verhält: Dazu zählen das schnelle Deployment von Serverless-Containern, das automatische Up- and Down-Scaling (bei Bedarf bis auf Null), das Routing und die Netzwerkprogrammierung für die Istio-Komponenten.

Knative deployt die Objekte unter dem jeweiligen Serving-Namespace. In der Knative Serving API hat ein Ressourcenpfad folgendes standardisiertes Kubernetes-Format:

/apis/{apiGroup}/{apiVersion}/namespace/{metadata.namespace}/{kind}/{metadata.name}

Die Route benennt den Netzwerkendpunkt für den User Service namentlich. Dabei erwartet Knative, dass die Route einen Namen zur Verfügung stellt, den Knative innerhalb des Cluster-weiten DNS-Systems zuordnet. Mit den Mechanismen des Kubernetes-Namespace lässt sich das einfach umsetzen, um eine URL nach folgendem Schema zu erzeugen:

[$revisionname].$route.$namespace.<common knative cluster suffix>

Die Service-Ressource der Knative-Serving-Komponente verwaltet (service.serving.knative.dev) den gesamten Lebenszyklus eines Workloads. Sie generiert Objekte, damit die Applikation eine Route sowie Konfigurationen hat und nach jedem Service-Update eine Revision stattfindet. Die Route-Ressource (route.serving.knative.dev) mapt einen Netzwerkendpunkt zu einer oder mehreren Revisionen. Damit lassen sich Deployment-Szenarien umsetzen, in denen Entwickler flexibel festlegen können, welche Revision welchen Anteil an der Ausspielung haben soll. Entwickler könnten etwa eine neue Revision in zehn Prozent der Fälle anstoßen und die alte Revision in 90 Prozent.

Die Configuration-Ressource (configuration.serving.knative.dev) stellt sicher, dass der gewünschte Status (desired state) des Deployments bestehen bleibt. Da durch jede Änderung an der Konfiguration eine neue Revision entsteht, lässt sich mit der Revision-Ressource (revision.serving.knative.dev) ein eindeutiger Point-in-Time-Snapshot von Code und Konfiguration erstellen.

Serving stellt eine durch Anfragen gesteuerte Scale-to-Zero Compute Runtime zur Verfügung und nutzt Istio, um den Workload routen zu können. Der folgende Code zeigt ein einfaches Kubernetes-Beispiel, das eine Basisvariante einer Scale-to-Zero-Instanz für einen Container kreiert und das korrespondierende Istio-Routing nutzt Quelle des Codes: Paul Czarkowski:

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: autoscale-go
namespace: default
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: samples/autoscale-go

Ein Blick auf die Build-Komponente

Die Knative-Build-Komponente übernimmt das Erstellen von Containern aus dem Sourcecode. Die Übergabe eines Dockerfile ist nicht notwendig. Die Buildpacks (https://buildpacks.io), Bazel (https://bazel.build) oder Buildah (https://github.com/knative/build-templates) erzeugen die Container auf dem Kubernetes-Cluster. Ziel ist es, eine standardisierte, portable, wiederverwendbare und performante Methode dafür zur Verfügung zu stellen.

Während Build-Template (build-template.build.knative.dev) Parameter und Abarbeitungsschritte definiert, stellt Build (build.build.knative.dev) die Verbindung zu einer Quelle her, definiert die Argument Values für die Parameter und berichtet den Status jedes Schritts. Ein Builder (builder.build.knative.dev) ist ein Container-Image, mit dem sich Steps und Prozesse vollendet ausführen lassen, und mit einem Service-Account (serviceaccount.build.knative.dev) findet eine Authentifizierung mit Kubernetes Secrets statt. Knative Builds ist auf das Erstellen, Testen und Deployen von Sourcecode spezialisiert – es gibt noch einige Dinge, um die sich Entwickler kümmern müssen. Zwar übernimmt das Buildpack etwa die Abfrage des Sourcecode, dafür ist aber die Übergabe der Repository-URL notwendig.

Da Knative Custom Resource Definitions (CRD) nutzt, ist der Aufruf eines Build unkompliziert: und zwar durch ein Kubernetes-Manifest, das das Build-Template (im Beispiel das Template Kaniko, das Docker Images erzeugen kann, ohne dass Docker installiert ist) und die Source Location spezifiziert.

apiVersion: build.knative.dev/v1alpha1
kind: Build
metadata:
name: kaniko-build
spec:
serviceAccountName: build-bot
source:
git:
url: https://github.com/my-user/my-repo
revision: master
template:
name: kaniko
arguments:
• name: IMAGE
value: us.gcr.io/my-project/my-app

Eventing mit Knative

Um das Deployment und das Management von Events kümmert sich die Knative-Eventing-Komponente. Knative basiert grundsätzlich auf einem eventgetriebenen Modell für das Ausführen von Funktionen, sodass der Komponente eine besondere Bedeutung zukommt. Laut ihrer Definition sollen sich ihre Ressourcen um die üblichen Herausforderungen der Cloud-nativen Entwicklung kümmern. Dazu gehören etwa die lose Kopplung zwischen Event-Bereitstellern und den Event-Empfängern oder flexibel kombinierbare Workflows (flow.eventing.knative.dev), die über unabhängig voneinander skalierende Komponenten hinweg funktionieren. Sie sind notwendig, um Events wie Channels (channel.eventing.knative.dev) oder Subscriptions (subscription.eventing.knative.dev) zu transportieren.

Zudem stellt Knative-Eventing Schnittstellen für Messaging/Data-Pipeline-Dienste wie Apache Kafka und Google Cloud Pub/Sub bereit. Mit den Bausteinen lassen sich komplexe Enterprise Integration Patterns umsetzen. Das folgende Beispiel erzeugt einen Feed an Kubernetes-Events und reicht ihn an die Applikation weiter, die auf Basis einer Serving-Komponente namens read-k8s-events läuft:

apiVersion: flows.knative.dev/v1alpha1
kind: Flow
metadata:
name: k8s-event-flow
namespace: default
spec:
serviceAccountName: feed-sa
trigger:
eventType: dev.knative.k8s.events
resource: k8sevents/dev.knative.k8s.event
service: k8events
parameters:
namespace: default
action:
target:
kind: Route
apiVersion: serving.knative.dev/v1alpha1
name: read-k8s-events

Alle Knative-Komponenten funktionieren unabhängig voneinander, ergänzen sich aber. Auf GitHub sind zahlreiche Samples und Issue-Listen verfügbar, weitere Entwicklungen aus der Open-Source-Community sind zu erwarten.

Kommunikationssicherheit dank Istio

Vor allem Google macht sich stark für die Idee, unterhalb einer Container-Plattform eine flache Netzwerkhierarchie, also weniger Firewalls, zu implementieren. Der Verminderung von Hardwaresicherheit müssen Entwickler mit erhöhter Sicherheit auf Softwareebene begegnen. Istio ist ein Service-Mesh, das Microservices ein Vehikel an die Hand geben will, damit sie die Vertrauenswürdigkeit einer Quelle beurteilen können. Die softwaredefinierte Kommunikationsmöglichkeit basiert auf Zertifikaten, die eine zentrale Autorität ausstellt. Dadurch können Sender und Empfänger sicher sein, dass der andere wirklich der ist, der er vorgibt zu sein.

Gerade bei nativ in der Cloud entwickelten Microservices wird das Aufrufverhalten untereinander schnell komplex. Istio hilft, den Überblick und die Kontrolle zu behalten. Das macht es zu einer guten Basis für Knative.

Was bedeutet das für Entwickler?

Knative kommt aus dem Universum der Microservices und Container. Entwickler, die aus der klassischen Anwendungsentwicklung stammen und jetzt vermehrt Microservices entwickeln, mussten ihre Denkweise umstellen. Trafen sie früher stets Annahmen, dass bestimmte Bedingungen wie Betriebssystem, Hardware und Ähnliches für die Anwendung vorhanden sind, geht es bei der Entwicklung von Microservices um das Übergeben von Daten und das Auslösen von Events.

Mit Knative erstellen Entwickler keine kompletten Anwendungen. Für diejenigen, die sich im Microservices-Kosmos bewegen, ist Knative ein nützliches, zusätzliches Tool. Kenntnisse und Erfahrungen mit Kubernetes und Containern sollten vorhanden sein.

Für Entwickler, die mit dem Open-Source-Projekt Riff vertraut sind, ist Knative gewissermaßen eine Weiterentwicklung. Denn Riff beschäftigte sich ebenfalls mit der Erweiterung von Kubernetes und stellte Services für das Event-getriggerte Ausführen von Funktionen zur Verfügung. Die Riff CLI erlaubt es, auf einfache Art und Weise mit der Knative-API zu interagieren und mehrere Ressourcen auf einmal anzulegen. Das Projekt geht nun vollständig in Knative auf.

Fazit

Es dauert wohl noch eine Weile, aber Serverless Computing wird eine neue Dimension von Anwendungsarchitekturen ermöglichen. Durch die Entwicklungen im IoT-Umfeld (Internet der Dinge) könnte das Serverless-Konzept Schwung bekommen. Denn gerade Sensoren sind meist nicht besonders stark bei der Verarbeitung von Daten – was sie ja nicht unbedingt sein müssen – können ihre Daten aber an Funktionen absetzen. Diese übernehmen dann die Datenaggregation, das Daten-Filtering oder Ähnliches. Der Vorteil: Funktionen lassen sich horizontal beliebig skalieren. Wenn beispielsweise Millionen von Autos geografisch verteilt riesige Mengen an Daten generieren, könnten unterschiedliche Rechenzentren sie flexibel entgegennehmen: je nachdem, welches Rechenzentren gerade örtlich am nächsten liegt oder welches derzeit die benötigten Kapazitäten zum besten Preis bietet.

Derzeit gleicht der Weg hin zu Serverless eher einem Weg ins Public-Cloud-Chaos. AWS Lambda oder Microsofts Azure Functions, um nur zwei der Tools für Serverless-Architekturen zu nennen, sind kaum miteinander integrierbar. Die Migration zwischen den Clouds ist nur schwer möglich. Unternehmen sind jedoch besser beraten, wenn sie sich nicht von einem einzigen Provider abhängig machen und dürften deshalb daran interessiert sein, die Migrationsfähigkeit und somit die Flexibilität zwischen unterschiedlichen Rechenzentren zu erhalten. Knative will genau diese Abstraktionsebene sein. (bbo)

Links

Jürgen Hoffmann
ist Senior Manager für Platform Architecture bei Pivotal.