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.