Es ist Zeit, serverless zu werden, zumindest fuer mich. Als Entwickler moechte ich Anwendungscode schreiben und ihn so schnell wie moeglich “irgendwo” zum Laufen bringen.

Ich moechte waehrend der Entwicklung nicht die Huete wechseln, nur um meinen Code in eine Cloud zu bekommen, indem ich neue Docker-Images erstelle und Kubernetes-Konfigurationen aendere.

Ja, natuerlich koennte ich ein CI-System einrichten, aber manchmal ist das etwas zu viel fuer eine lokale Entwicklungsumgebung.

Das Serverless-Paradigma geht meiner Meinung nach in die richtige Richtung. Zeit, ein Gefuehl dafuer zu bekommen.

Ich habe Kubeless als Framework gewaehlt, weil ich auf meinem lokalen k3s-Cluster spielen moechte.

Von ihrer Website beschreiben sie es wie folgt:

Kubeless is a Kubernetes-native serverless framework that lets you deploy small bits of code (functions) without having to worry about the underlying infrastructure. It is designed to be deployed on top of a Kubernetes cluster and take advantage of all the great Kubernetes primitives. If you are looking for an open source serverless solution that clones what you can find on AWS Lambda, Azure Functions, and Google Cloud Functions, Kubeless is for you!

Daher ist dieser Beitrag ein Tutorial ueber das Kubeless-Framework, um zu erkunden, was es bedeutet, serverless Funktionen zu deployen.

Genug gesagt, lass uns direkt einsteigen.

Eine Sekunde: Bevor wir anfangen, muss ich erwaehnen, dass mein Setup folgendes ist:

  • ein MacBook Pro als lokale Workstation
  • ein Zwei-Knoten k3s-Cluster, der auf Ubuntu laeuft

Wenn dein Setup sehr unterschiedlich ist, schau bitte auf der Kubeless-Website nach (Links am Ende dieses Beitrags).

Installation

Zuerst installieren wir alles mit den folgenden Befehlen:

$ export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kubeless/releases/latest | grep tag_name | cut -d '"' -f 4)
$ kubectl create ns kubeless
$ kubectl create -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml

Wie jedes gute Tool kommt auch Kubeless mit seiner eigenen CLI, um die Dinge etwas einfacher zu machen:

$ 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/

Pruefe, ob es richtig installiert wurde mit:

$ kubeless version

Lass uns mit dem Deployment einiger Funktionalitaet fortfahren.

Deployment einer Funktion

Jetzt werden wir diese “kleinen Code-Stuecke” deployen, die zuvor erwaehnt wurden - die sogenannten “Funktionen”.

Erstelle den Code in einer Datei namens echo.py:

def echo(event, context):
 print(event)
 return event['data']

Dann deploye ihn auf den Cluster mit:

$ kubeless function deploy echo --runtime python3.8 --from-file echo.py --handler echo.echo

Das ist alles!

Mache eine schnelle Ueberpruefung, ob die Funktion ordnungsgemaess erstellt wurde:

$ kubeless function ls echo
NAME NAMESPACE 	HANDLER 	RUNTIME 	DEPENDENCIES 	STATUS
echo	 default 	echo.echo	python3.8	   	 1/1 READY

Pruefe besonders die letzte Spalte: Der STATUS sollte READY sein.

Wenn es nicht funktioniert, schau bitte im Abschnitt “Fehlerbehebung” nach.

Test

Teste schliesslich die Funktion, indem du sie ueber kubeless aufrufst:

$ kubeless function call echo --data 'Hello World!'
Hello World!

Erfolg!

Aufraeumen

Wenn du alles wieder entfernen moechtest, hier sind die Befehle, um das Installierte zu bereinigen:

$ kubeless function delete echo
$ kubectl delete -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml
$ kubectl delete ns kubeless

Kubeless ohne kubeless verwenden

Was fuer ein seltsamer Titel, aber er macht nach dem Lesen dieses Abschnitts Sinn.

Wir sind immer noch auf Kubernetes und alles funktioniert ohne die zusaetzliche CLI. Eine Kubeless-Funktion ist in Kubernetes-Begriffen eine Custom Resource (CRD). Daher werden Kubeless-Funktionen zu Kubernetes-Objekten und wir koennen kubectl wie gewohnt verwenden.

Lass es uns ausprobieren.

Loesche zuerst die vorherige Funktion, falls du das noch nicht getan hast (siehe “Aufraeumen”).

Fuege Folgendes in eine Datei namens echo.yaml ein:

---
apiVersion: kubeless.io/v1beta1
kind: Function
metadata:
 name: echo
spec:
 deployment:
 metadata:
  annotations:
  "annotation-to-deploy": "value"
 spec:
  replicas: 2
  template:
  metadata:
   annotations:
   "annotation-to-pod": "value"
 deps: ""
 function: |
 def echo(event, context):
  print(event)
  return event['data']
 function-content-type: text
 handler: echo.echo
 runtime: python3.8
 service:
 selector:
  function: echo
 ports:
 - name: http-function-port
  port: 8080
  protocol: TCP
  targetPort: 8080
  nodePort: 30333
 type: NodePort

Dann installiere es auf dem Cluster:

$ kubectl apply -f echo.yaml

Pruefe, ob es deployed wurde:

$ kubectl get svc echo
NAME TYPE  CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo ClusterIP WW.XX.YYY.Z <none>  8080/TCP 16m

Alles in Ordnung!

Um den Service zu testen, leite den Port des Cluster-Knotens auf deinen lokalen Rechner weiter:

$ kubectl port-forward service/echo 8080:8080

Dann, in einem anderen Terminal, curl in den Cluster, um die Funktion aufzurufen:

$ curl -L --data '{"echo":"Hello World!"}' --header "Content-Type:application/json" localhost:8080/api/v1/namespaces/default/services/echo:http-function-part/proxy/

Et voila - da ist die Ausgabe. Falls nicht, fahre mit dem naechsten Abschnitt fort.

Fehlerbehebung

Es ist wahrscheinlich, dass beim ersten Durchlaufen dieses Tutorials etwas nicht wie erwartet funktioniert. Ich bin nach dem Deployment meiner ersten Funktion auf ein Problem gestossen: Der Service war nicht erreichbar und ich konnte die Funktion nicht aufrufen.

Wenn du deine Funktion ueberpruefst, koennte der Status “NOT READY” statt “READY” sein, und der zugehoerige Pod koennte in “CrashLoopBackOff” stecken bleiben.

Der uebliche Ansatz ist, die Logs des Kubernetes-Pods zu pruefen.

Hole zuerst den Pod-Namen:

$ kubectl get pods
NAME  READY STATUS  RESTARTS AGE
echo-xzy 1/1  Running  0   4m35s

Dann hole die Logs:

$ kubectl logs echo-xzy

Erst dann konnte ich herausfinden, dass ich eine Python-Version gewaehlt hatte, die nicht mehr verfuegbar war; ich musste auf eine hoehere Version (>= 3.x) wechseln. Ich musste auch meine Code-Syntax aendern, weil dies in Python 2 gueltig ist:

print "Hello World!"

aber in Python 3 muss es sein:

print("Hello World!")

Nur zum Spass.

Fazit

Hoffentlich war dein erster Ausflug in Serverless erfolgreich. Ich habe es genossen und sehe viele Moeglichkeiten, meinen Entwicklungsworkflow zu optimieren.

Erkunde jetzt weitere existierende Funktionen und schreibe einige eigene. Ich habe unten einige Links eingefuegt, um dich am Laufen zu halten.

Gerne kannst du mir einen Kaffee kaufen, wenn dir dieser Beitrag gefallen hat.

Ressourcen