Erste Schritte für das Erstellen von Serverless-Anwendungen mit Knative

© Shutterstock / Artur Balytskyi
In diesem Artikel werden die ersten Schritte für das Erstellen von Serverless-Anwendungen mit Knative vorgestellt. Das Tutorial reicht vom Aufsetzen eines Minikube über das Erstellen einer Kubernetes-Ressourcendatei bis hin zum Deployment der Serverless-Anwendung.
Im ersten Teil des Artikels werden wir uns mit dem Aufsetzen einer Entwicklungsumgebung beschäftigen, die für Knative in Version 0.6.0 geeignet ist. Im zweiten Teil geht es dann um das Deployment des ersten eigenen Serverless Microservice. Grundvoraussetzung für die Nutzung von Knative für das Erstellen von Serverless-Anwendungen ist eine solide Kenntnis von Kubernetes. Wer darin noch unerfahren ist, sollte das offizielle Basis-tutorial von Kubernetes [1] absolvieren. Bevor es ans Eingemachte geht, müssen noch ein paar Tools und Utilities installiert werden:
-
Minikube [2]
-
kubectl [3]
-
kubens [4]
Für Windows-Nutzer hat sich WSL [5] als ziemlich nützlich erwiesen, ich empfehle, das auch noch zu installieren.
Aufsetzen von Minikube
Minikube ist ein Kubernetes-Cluster mit einem einzigen Knoten, der sich hervorragend für die alltägliche Entwicklung mit Kubernetes eignet. Nach der Installation müssen die folgenden Schritte durchgeführt werden, um Minikube fit für ein Deployment mit Knative Serving zu machen. Wie das im Code aussieht, zeigt Listing 1.
minikube profile knative minikube start -p knative --memory=8192 --cpus=6 \ --kubernetes-version=v1.12.0 \ --disk-size=50g \ --extra-config=apiserver.enable-admission-plugins="LimitRanger,NamespaceExists,NamespaceLifecycle,ResourceQuota,ServiceAccount,DefaultStorageClass,MutatingAdmissionWebhook"
Zunächst muss ein Minikube-Profil angelegt werden, wofür die erste Zeile steht. Anschließend wird mit dem zweiten Befehl eine Minikube-Instanz aufgesetzt, die 8 GB RAM, 6 CPUs und 50 GB Festplattenspeicher erhält. Der Startbefehl beinhaltet zudem ein paar zusätzliche Konfigurationen für den Kubernetes-Cluster, die nötig sind, um Knative zum Laufen zu bekommen. Wichtig ist auch, dass die verwendete Kubernetes-Version nicht älter als Version 1.12.0 ist, sonst funktioniert Knative nicht. Startet Minikube nicht sofort, ist das völlig normal: Es kann ein paar Minuten dauern, bis der initiale Start abgeschlossen ist, ein wenig Geduld sollte man beim Aufsetzen also mitbringen.
Aufsetzen eines Istio Ingress Gateways
Knative benötigt ein Ingress Gateway, um Requests an Knative Services zu routen. Neben Istio [6] wird auch Gloo [7] als Ingress Gateway unterstützt. Für unser Beispiel werden wir allerdings Istio nutzen. Die folgenden Schritte zeigen, wie man eine möglichst leichtgewichtige Installation von Istio durchführt, die ledgiglich das Ingress Gateway enthält:
curl -L https://raw.githubusercontent.com/knative/serving/release-0.6/third_party/istio-1.1.3/istio-lean.yaml \
| sed 's/LoadBalancer/NodePort/' \
| kubectl apply --filename -
Wie bereits das Aufsetzen von Minikube, dauert auch das Deployment des Istio Pods ein paar Minuten. Mit dem Befehl kubectl –namespace istio-system get pods –watch kann man sich den Status ansehen, beendet wird die Übersicht mit STRG + C. Ob das Deployment erfolgreich war, lässt sich leicht mit dem Kommando kubectl –namespace istio-system get pods feststellen. Ist alles gut gelaufen, sollte die Ausgabe es wie in Listing 2 aussehen.
NAME READY STATUS RESTARTS AGE cluster-local-gateway-7989595989-9ng8l 1/1 Running 0 2m14s istio-ingressgateway-6877d77579-fw97q 2/2 Running 0 2m14s istio-pilot-5499866859-vtkb8 1/1 Running 0 2m14s
Installation von Knative Serving
Die Installation von Knative Serving [8] erlaubt es uns, Serverless Workloads auf Kubernetes laufen zu lassen. Darüber hinaus stellt es automatische Skalierung und automatisches Tracking von Revisionen bereit. Mit den folgenden Befehlen lässt sich Knative Serving installieren:
kubectl apply --selector knative.dev/crd-install=true \
--filename https://github.com/knative/serving/releases/download/v0.6.0/serving.yaml
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.6.0/serving.yaml --selector networking.knative.dev/certificate-provider!=cert-manager
Auch hier wird es vermutich einige Minuten dauern, bis die Knative Pods deployt werden. Mit dem Kommando kubectl –namespace knative-serving get pods –watch kann man den Status überprüfen, und wie gehabt wird die Überprüfung mit STRG + C abgebrochen. Mit dem Kommando kubectl –namespace knative-serving get pods lässt sich auch in diesem Fall kontrollieren, ob alles läuft. Ist das der Fall, sollte eine Ausgabe wie in Listing 3 angezeigt werden.
NAME READY STATUS RESTARTS AGE activator-54f7c49d5f-trr82 1/1 Running 0 27m autoscaler-5bcd65c848-2cpv8 1/1 Running 0 27m controller-c795f6fb-r7bmz 1/1 Running 0 27m networking-istio-888848b88-bkxqr 1/1 Running 0 27m webhook-796c5dd94f-phkxw 1/1 Running 0 27m
Deployment einer Anwendung
Die Anwendung, die wir zur Demonstration erstellen wollen, ist eine einfache Begrüßungsautomatik, die „Hi“ ausgibt. Hierfür nutzen wir ein bestehendes Linux-Container-Image, das unter [9] zu finden ist.
Der erste Schritt ist es, ein traditionelles Kubernetes Deployment zu erstellen, das anschließend für die Nutzung von Serverless-Funktionalitäten modifiziert werden kann. Dadurch wird deutlich werden, worin die eigentlichen Unterschiede liegen und wie man existierende Deployments unter Zuhilfenahme von Knative serverless macht.
Erstellen einer Kubernetes-Ressourcendatei
Die folgenden Schritte zeigen, wie wir eine Kubernetes-Ressourcendatei erstellen können. Dazu muss zunächst eine neue Datei mit dem Namen app.yaml erstellt werden, in die der in Listing 4 aufgeführte Code kopiert werden muss.
--- apiVersion: apps/v1 kind: Deployment metadata: name: greeter spec: selector: matchLabels: app: greeter template: metadata: labels: app: greeter spec: containers: - name: greeter image: quay.io/rhdevelopers/knative-tutorial-greeter:quarkus resources: limits: memory: "32Mi" cpu: "100m" ports: - containerPort: 8080 livenessProbe: httpGet: path: /healthz port: 8080 readinessProbe: httpGet: path: /healthz port: 8080 --- apiVersion: v1 kind: Service metadata: name: greeter-svc spec: selector: app: greeter type: NodePort ports: - port: 8080 targetPort: 8080
Erstellen des Deployments und des Service
Indem wir die zuvor erstellte YAML-Datei anwenden, können wir das Deployment und den Service erstellen. Dazu wird der Befehl kubectl apply –filename app.yaml verwendet. Auch an dieser Stelle kann das Kommando kubectl get pods –watch genutzt werden, um sich über den Status der Anwendung zu informieren, während STRG + C das Ganze beendet. Ist alles gut gegangen, steht uns ein Deployment mit dem Namen greeter und ein Service namens greeter-svc zur Verfügung (Listing 5).
$ kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE greeter 1 1 1 1 16s $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE greeter-svc NodePort 10.110.164.179 <none> 8080:31633/TCP 50s
Um einen Service zu aktivieren, kann man hier auch einen Minikube Shortcut wie minikube service greeter-svc nutzen, der den Service URL im Browser öffnet. Wer lieber curl nutzen möchte, um den gleichen URL aufzurufen, muss das Kommando curl $(minikube service greeter-svc –url) verwenden. Nun sollte ein Text angezeigt werden, der in etwa so aussieht: Hi greeter => ‚9861675f8845‘ : 1
Migration des traditionellen Kubernetes Deployments zu Serverless mit Knative
Die Migration startet ganz einfach damit, dass wir die Datei app.yaml kopieren, sie serverless-app-yaml nennen und sie um die in Listing 6 gezeigten Zeilen aktualisieren.
--- apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: greeter spec: template: metadata: labels: app: greeter spec: containers: - image: quay.io/rhdevelopers/knative-tutorial-greeter:quarkus resources: limits: memory: "32Mi" cpu: "100m" ports: - containerPort: 8080 livenessProbe: httpGet: path: /healthz readinessProbe: httpGet: path: /healthz
Vergleicht man die traditionelle Kubernetes-Anwendung (app.yaml) mit der Serverless-Anwendung (serverless-app.yaml), stellt man drei Dinge fest. Zum einen wird kein zusätzlicher Service benötigt, da Knative den Service automatisch erstellen und routen wird. Da die Definition des Service manuell erfolgt, braucht es keine Selektoren mehr, folgende Codezeilen fallen also weg:
selector:
matchLabels:
app: greeter
Unter template.spec.containers fällt name: weg, da der Name von Knative automatisch generiert wird. Außerdem müssen für die Probes liveness und readiness keine Ports definiert werden.
Deployment der Serverless-Anwendung
Das Deployment läuft nach dem gleichen Muster ab wie bisher, dazu wird der Befehl kubectl apply –filename serverless-app.yaml angewandt. Die folgenden Objekte sollten erstellt worden sein, wenn das Deployment der Serverless-Anwendung erfolgreich abgeschlossen wurde: Zunächst sollte das Deployment jetzt hinzugefügt worden sein (Listing 7). Auch ein paar neue Services sollten verfügbar sein (Listing 8), unter anderem der Service ExternalName, der auf istio-ingressgateway.istio-system.svc.cluster.local zeigt. Es sollte zudem ein Knative Service mit einem URL verfügbar sein, an den Requests gesendet werden können (Listing 9).
$ kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE greeter 1 1 1 1 30m greeter-bn8cm-deployment 1 1 1 1 59s
$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE greeter ExternalNameistio-ingressgateway.istio-system.svc.cluster.local 114s greeter-bn8cm ClusterIP 10.110.208.72 80/TCP 2m21s greeter-bn8cm-metrics ClusterIP 10.100.237.125 9090/TCP 2m21s greeter-bn8cm-priv ClusterIP 10.107.104.53 80/TCP 2m21s
kubectl get services.serving.knative.dev NAME URL LATESTCREATED LATESTREADY READY REASON greeter http://greeter.default.example.com greeter-bn8cm greeter-bn8cm True
Wichtig
In einem Minikube Deployment werden wir weder LoadBalancer noch DNS haben, um etwas nach *.example.com oder einem Service-URL wie http://greeter.default.example.com aufzulösen. Um einen Service aufzurufen, muss der Header vom Host mit http/curl genutzt werden.
Um nun einen Service aufrufen zu können, muss der Request durch den Ingress bzw. das Gateway (in unserem Fall Istio) gehen. Um die Adresse des Istio Gateways herauszufinden, die wir im http/curl Call nutzen müssen, kann das folgende Kommando genutzt werden:
IP_ADDRESS="$(minikube ip):$(kubectl get svc istio-ingressgateway --namespace istio-system --output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')"
Der Befehl erhält den NodePort des Service istio-ingressgateway im Namespace istio-system. Wenn wir den NodePort des istio-ingressgateway haben, können wir den Service greeter via $IP_ADDRESS aufrufen, indem wir den Hostheader mit http/curl Calls passieren.
curl -H "Host:greeter.default.example.com" $IP_ADDRESS
Nun sollte man die gleiche Antwort wie beim traditionellen Kubernetes Deployment erhalten (Hi greeter => ‚9861675f8845‘ : 1). Erlaubt man dem Deployment, sich für etwa 90 Sekunden im Idle-Modus zu befinden, wird das Deployment terminiert. Beim nächsten Call wird das terminierte Deployment dann wieder aktiviert und den Request beantworten.
Herzlichen Glückwunsch, ihr habt eure erste Serverless-Anwendung erfolgreich deployt und aufgerufen!
Links & Literatur
- [1] https://kubernetes.io/docs/tutorials/kubernetes-basics/
- [2] https://kubernetes.io/docs/tasks/tools/install-minikube/
- [3] https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-on-linux
- [4] https://github.com/ahmetb/kubectx/blob/master/kubens/
- [5] https://docs.microsoft.com/en-us/windows/wsl/install-win10
- [6] https://istio.io
- [7] https://gloo.solo.io
- [8] https://knative.dev/docs/serving/
- [9] https://quay.io/rhdevelopers/knative-tutorial-greeter
Hinterlasse einen Kommentar