6
© iStockphoto.com/Vladyslav Otsiatsia magazin JAVA Mag www.javamagazin.de Cloud-native Anwendungen mit Kubernetes S. 76 Vert.x: Eine reaktive Lösung S. 59 Groove your Jenkins S. 44 Ausgabe 8.2016 Programminfos ab Seite 35! Java | Architektur | Software-Innovation Machine Learning Warum sich Entwickler damit beschäftigen sollten

Cloud-native Anwendungen mit Kubernetes

Embed Size (px)

Citation preview

Page 1: Cloud-native Anwendungen mit Kubernetes

© iS

tock

phot

o.co

m/V

lady

slav

Ots

iats

ia

magazinJAVA

Mag

www.javamagazin.de

Cloud-native Anwendungen mit Kubernetes S. 76

Vert.x: Eine reaktive Lösung S. 59

Groove your Jenkins S. 44

Ausgabe 8.2016

Programminfos

ab Seite 35!

Java | Architektur | Software-Innovation

Machine LearningWarum sich Entwickler damit beschäftigen sollten

Page 2: Cloud-native Anwendungen mit Kubernetes

javamagazin 8 | 2016

Anwendungen mit KubernetesCloud

Computing

2 www.JAXenter.de

von Dr. Josef Adersberger und Mario-Leander Reimer

Kubernetes (kurz: K8s [1]) ist ein quelloffener Clusteror-chestrierer, der maßgeblich von Google entwickelt wird und Mitte 2015 in der Version 1.0 erschienen ist. Das bedeutet, dass K8s für den Einsatz in Produktion freige-geben ist, was Google selbst und weitere Unternehmen wie die New York Times bereits tun. Rund um K8s hat sich mittlerweile die Cloud Native Computing Founda-

tion (CNCF [2]) unter dem Dach der Linux Foundation formiert. K8s ist die CNCF-Referenzimplementierung eines Clusterorchestrierers. Damit stehen nun hinter K8s neben Google auch weitere namhafte Unternehmen wie Mesosphere, Cisco, IBM und Intel.

Doch was ist K8s genau? K8s ist ein Clusterorches-trierer, ein Applikationsserver, der Anwendungen auf einem potenziell sehr großen Cluster ausführt – auf ei-ner Cloud. K8s agiert dabei auf der Abstraktionsebene von Anwendungen und ihren angebotenen Services, sitzt also exakt an der Schnittstelle zwischen Devs und Ops. Die Anwendungen sind dabei oft Microservices. Es sind jedoch auch andere Anwendungen gern auf K8s gese-hen, Hauptsache man kann sie in einem Docker- oder rkt-Container verpacken, wie es auch für klassische JEE-Anwendungen gelingt.

K8s betreibt Anwendungen automatisch. Er besitzt eine Steuerschnittstelle (REST-API, Kommandozeile

Artikelserie

Teil 1: Der Cloud-Native-StackTeil 2: Cloud-native Anwendungen mit Spring Cloud und Netflix OSS bauenTeil 3: Cloud-native Anwendungen mit KubernetesTeil 4: Mesos: Das Betriebssystem der Cloud

Kubernetes (griechisch „Steuermann“) ist ein Open-Source-Projekt aus der Feder von Google und im Prinzip ein Applikationsserver der Ära Cloud: für Microservices und alle anderen Anwen-dungen, die sich in Container zwängen lassen und auf einem Cluster laufen. Anwendungen sol-len dabei so skalieren, resilient und effizient zu betreiben sein wie diejenigen von Google. Ein großes Versprechen, das wir im Rahmen dieses Artikels beleuchten.

© iS

tock

phot

o.co

m/g

rem

lin

Teil 3: Cloud-native Anwendungen mit Kubernetes

Steuermann, grüß mir die Wolken

Page 3: Cloud-native Anwendungen mit Kubernetes

javamagazin 8 | 2016

Anwendungen mit Kubernetes

3

Cloud Computing

www.JAXenter.de

und Web-UI), mit der die Automatismen angestoßen werden können und der aktuelle Status abgerufen wer-den kann. Was K8s automatisiert:

• Container auf dem Cluster ausführen• Netzwerkverbindungen zwischen Containern aufbauen• Persistenten Speicher (Persistent Volumes) für zu-

standsbehaftete Container bereitstellen• Konfigurationsparameter, Schlüssel und Passwörter

definieren, ändern und bereitstellen• Roll-out-Workflows wie Canary Roll-outs automati-

sieren• Performance und Verfügbarkeit von Serviceendpunk-

ten überwachen und Container bei zu geringer Per-formance skalieren (Auto-Scaling) und im Fehlerfall reschedulen (Self-Healing)

• Services managen: Service Discovery, Naming und Load Balancing

Anwendungen deklarativ beschreibenK8s macht all das auf Basis einer Anwendungsblaupause, die beim Deployment einer Anwendung mit überreicht wird. Diese Anwendungsblaupause beschreibt den Ziel-zustand einer Applikation im Cluster. Aufgabe von K8s ist es dann, das Cluster vom aktuellen Zustand in den Zielzustand zu überführen. Die Anwendungsblaupause macht dabei keine Annahmen über das Cluster, sondern stellt lediglich Ressourcenforderungen. Somit sind An-wendungen portierbar: Egal ob K8s nur einen Laptop, eine Private Cloud oder gar die große weite Public Cloud unter seinen Fittichen hat, solange genügend Ressourcen zur Verfügung stehen, läuft die Anwendung ohne An-passung überall. Eine Anwendungsblaupause besteht bei K8s aus den folgenden Elementen, die über YAML- oder JSON-Dateien beschrieben werden (Abb. 1):

• Pod: Gruppe an Containern, die auf demselben Knoten laufen und sich eine Netzwerkschnittstelle inklusive einer dedizierten IP, persistente Volumes und Umgebungsvariablen teilen. Ein Pod ist die ato-mare Scheduling-Einheit in K8s. Ein Pod kann über

sogenannte Labels markiert werden. Das sind frei definierbare Schlüssel-Wert-Paare.

• Service: Endpunkt unter einem definierten DNS-Na-men, der Aufrufe an Pods verteilt. Die für einen Service relevanten Pods werden über ihre Labels selektiert (z. B. role = apache, env != test, tier in (web, app)).

• ReplicaSet (bzw. veraltetes Konstrukt Replication Controller): Stellt sicher, dass eine spezifizierte Anzahl an Instanzen pro Pod ständig läuft. Ist für Reaktionen im Fehlerfall, Skalierung und Roll-outs zuständig.

• Deployment: Klammer um einen gewünschten Ziel-zustand im Cluster in Form eines Pods mit dazugehö-rigem ReplicaSet. Ein Deployment bezieht sich nicht auf Services, da diese in der K8s-Philosophie einen von Deployments unabhängigen Lebenszyklus haben.

Die Architektur von KubernetesK8s selbst ist eine verteilte Anwendung. Abbildung 2 zeigt die Architektur von K8s. Der Masterknoten ist das Gehirn des Clusters, die normalen Nodes die Muskeln. Der Master orchestriert das Cluster, auf den Nodes laufen die Pods und Services. Auf dem Masterknoten läuft ein API-Server, über den die K8s-Automatismen per REST-API angestoßen werden können. Er bietet die zentrale Administrationsschnittstelle. Der Control-lermanager steuert die eigentliche Orchestrierung. Er führt Deployments und ReplicaSets (bzw. Replication-Controller) aus. Der Scheduler ist dafür zuständig, Pods auf die passenden Knoten zu verteilen. Er macht das entsprechend des Ressourcenbedarfs der Pods und den noch freien Ressourcen auf den Nodes. etcd ist ein verteilter konsistenter Konfigurationsspeicher – das Ge-dächtnis von K8s, in dem der aktuelle Clusterzustand verwaltet wird.

Auf den Nodes laufen drei Komponenten: Der kube- proxy, der sich um die Weiterleitung von Ser vice-auf rufen an die passenden Container kümmert; die Container-Engine, im Default ist es Docker, das Con-tainer ausführt; und das kubelet, ein Agent des Masters, der den Knoten verwaltet, steuert und mit dem Master kommuniziert. Neben K8s als Kernplattform ist mittler-

Abb. 1: Elemente einer Anwendungsblaupause Abb. 2: Architektur von Kubernetes

Page 4: Cloud-native Anwendungen mit Kubernetes

javamagazin 8 | 2016

Anwendungen mit KubernetesCloud

Computing

4 www.JAXenter.de

weile ein breites Ökosystem an Werkzeugen, Erweite-rungen und Frameworks rund um K8s entstanden:

• Prometheus [3], Weave Scope [4] und sysdig [5] für das Monitoring und die Fehlerdiagnose

• Helm [6] als Paketmanager für wiederverwendbare Applikationsteile

• Maven- und Gradle-Plug-ins sowie ein Java-API zur Fernsteuerung von K8s (http://fabric8.io)

Erste Schritte: Hands-on KubernetesDer Schritt hin zu ersten Erfahrungen mit K8s ist ein leichter. Es stehen mehrere vorgefertigte K8s-Instal-lationen zur Verfügung, z. B. über die Google-Contai-ner-Engine [7], für diverse Public IaaS Clouds oder als Vagrant-Boxen  [8]. Unter dem URL https://get.k8s.io steht ein Shellskript für die automatische Installation be-reit. Listing 1 zeigt ein Skript, mit dem ein lokales K8s-Cluster per Vagrant erstellt wird. Das funktioniert nur unter Linux und Mac, eine Installation unter Windows wird aktuell noch nicht unterstützt.

Sobald die Installation erfolgreich abgeschlossen ist, kann anschließend über das kubectl.sh-Kommandozei-lenwerkzeug mit dem Cluster interagiert werden (Lis-ting 2). In Zeile 1 und 2 werden sowohl Informationen über das Cluster als auch die aktuell laufenden Pods, Services und Deployments abgefragt. In Zeile 4 legen wir ein Deployment und einen Service an und in Zeile 6 ska-lieren wir das Deployment von zwei auf fünf Replicas.

Listing 3 zeigt die hierfür verwendete Anwendungs-blaupause: einen nginx-Server in zwei Instanzen. Zusätz-lich zum eigentlichen Deployment ist ein Service definiert, um auf die nginx-Instanzen über eine externe IP zugreifen

zu können und um die Last auf die beiden laufenden Pods zu verteilen. Über das Templateelement im Deployment wird der Pod definiert. Dabei können auch mehrere Con-tainer mit angegeben werden. Das ReplicaSet wird impli-zit über die Anzahl der Replicas definiert.

Die Kubernetisierung von ZwitscherIm nächsten Schritt wollen wir nun unseren Zwitscher-Showcase aus den vorherigen Artikeln dieser Serie mit-hilfe von K8s orchestrieren. Der erste Schritt ist die Containerisierung: Hier werden die einzelnen Microser-vices in Docker-Container gepackt und per Docker Re-gistry verfügbar gemacht. Listing 4 zeigt beispielhaft das Dockerfile für einen Zwitscher-Microservice, Listing 5, wie man daraus einen Container erzeugt und in eine Docker Registry lädt. Abbildung 3 zeigt alle Container sowie die verwendeten Basis-Images von Zwitscher.

Bei der Containerisierung sollte ein Punkt dringend beachtet werden: Kenne dein Basisimage! So bringt z. B. das java:8-Docker-Basis-Image stolze 800 MB auf die Waage. Bei sechs Microservices-Containern ist das eine Menge Holz, der Download der Images durch K8s dau-ert später unnötig lange. Abhilfe schafft hier z. B. die dockerisierte und kubernetisierte Version von Alpine Linux [9] oder ein eigenes maßgeschneidertes Image wie in Listing 5 zu sehen.

Nun steht die eigentliche Kubernetisierung unserer Anwendung an. Hierfür teilen wir unsere Container auf Pods auf. Alle Container eines Pods teilen dasselbe Schicksal: Sie werden gemeinsam gestartet und gemein-sam skaliert. Stirbt ein Container, sterben alle. Welche Container man zusammen in einen Pod packt, ist eine Architekturentscheidung: Welche Container haben ei-

nen gemeinsamen Lebenszyklus? Welche Container sollten möglichst nah beieinan-der laufen, um Overhead zu vermeiden? Ein bekanntes Pattern ist das Sidekick-Pattern, bei dem neben einem funktionalen Container (wie einem Microservice) noch weitere Container laufen, die dessen Funk-tionalität anreichern (z. B. ein Monitoring-Agent oder ein Logextraktor).Abbildung 4 zeigt die Pods sowie die de-

finierten Services und Abhängigkeiten von

Abb. 3: Dockerized Zwitscher Abb. 4: Kubernized Zwitscher

Listing 1

#!/bin/shexport KUBERNETES_PROVIDER=vagrantexport KUBE_ENABLE_CLUSTER_MONITORING=nonecurl -sS https://get.k8s.io | bash

Listing 2kubectl.sh cluster-infokubectl.sh get pods,services,deployments

kubectl.sh create -f nginx-deployment.ymlkubectl.sh get pods,services,deploymentskubectl.sh scale deployment nginx – replicas=5kubectl.sh get pods

Page 5: Cloud-native Anwendungen mit Kubernetes

javamagazin 8 | 2016

Anwendungen mit Kubernetes

5

Cloud Computing

www.JAXenter.de

Zwitscher in der Übersicht. Listing 6 zeigt die Definition für den Service und das Deployment unserer Zwitscher-Applikation.

Der Service kann später direkt über seinen Namen angesprochen werden. Beim Typ stehen ClusterIP, Node Port und LoadBalancer zur Auswahl. ClusterIP exponiert den Service nur innerhalb des Clusters. Im Fall von NodePort werden die Containerports eines Pods auf jeden K8s Node exportiert. Bei Verwendung von LoadBalancer wird eine externe, lastverteilte IP für diesen Service akquiriert, sofern das vom Cluster unter-stützt wird. Das Deployment definiert die Eigenschaften der Pods mit ihren Containern. In unserem Beispiel set-zen wir die initiale Anzahl an Replicas auf drei. Über die Template Spec definieren wir das Docker Image, die benötigten Ressourcen, Ports, Liveness Probes und die Umgebungsvariablen unserer Container. Die Liveness Probes nutzt K8s, um herauszufinden, ob ein Pod er-folgreich gestartet ist.

Alle YAML-Dateien für das kubernetisierte Zwitscher sind im Zwitscher-GitHub-Repository zu finden [10].

Nun können wir die Deployments und Services in K8s per Kommandozeile erzeugen (Listing 7).

K8s kennt derzeit keine Startabhängigkeiten und kei-ne Startreihenfolge der einzelnen Deployments. Dennoch benötigt der Zwitscher-Microservice eine gewisse Spring-

Listing 3

apiVersion: extensions/v1beta1kind: Deploymentmetadata: name: nginxspec: replicas: 2 template: metadata: labels: app: nginx tier: web spec: containers: - name: nginx image: nginx ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: nginx labels: app: nginx tier: webspec: # external load-balanced IP if provider supports it type: LoadBalancer ports: - port: 80 selector: app: nginx tier: web

Listing 5EXPOSE 8761ENTRYPOINT exec /opt/zwitscher-service/zwitscher-service.sh$ docker build -t zwitscher-service:1.1.0 .$ docker tag <IMAGE_ID> qaware-oss-docker-registry.bintray.io/zwitscher/ zwitscher-service:1.1.0$ docker push qaware-oss-docker-registry.bintray.io/zwitscher/zwitscher-service:1.1.0

Listing 4FROM qaware-oss-docker-registry.bintray.io/base/debian8-jre8MAINTAINER QAware GmbH <[email protected]>

RUN mkdir -p /opt/zwitscher-service

COPY build/libs/zwitscher-service-1.1.0.jar /opt/zwitscher-service/zwitscher-service.jarCOPY src/main/docker/zwitscher-service.* /opt/zwitscher-service/

RUN chmod 755 /opt/zwitscher-service/zwitscher-service.jar; chmod 755 /opt/ zwitscher-service/zwitscher-service.sh

Listing 6

apiVersion: v1kind: Servicemetadata: name: zwitscher-service labels: zwitscher: servicespec: # use NodePort to be able to access the # port on each node type: NodePort ports: - port: 8080 selector: zwitscher: service---apiVersion: extensions/v1beta1kind: Deploymentmetadata: name: zwitscher-servicespec: replicas: 3 minReadySeconds: 30 template: metadata: labels: zwitscher: service spec:

containers: - name: zwitscher-service image: "qaware-oss-docker- registry.bintray.io/zwitscher/ zwitscher-service:1.1.0" imagePullPolicy: IfNotPresent resources: requests: memory: "256Mi" cpu: "500m" limits: memory: "512Mi" cpu: "750m" ports: - containerPort: 8080 livenessProbe: httpGet: path: /admin/health port: 8080 initialDelaySeconds: 90 timeoutSeconds: 30 env: - name: EUREKA_HOST value: zwitscher-eureka - name: JAVA_OPTS value: -Xmx196m

Page 6: Cloud-native Anwendungen mit Kubernetes

javamagazin 8 | 2016

Anwendungen mit KubernetesCloud

Computing

6 www.JAXenter.de

Cloud-Infrastruktur, um sauber zu starten, wie Eureka und den Configuration-Service. Eine Lösung für dieses Problem ist es, den Start der Services per Retry-Mecha-nismus resilienter zu gestalten (Listing 8). Spring versucht dann in definierten, immer länger werdenden Abständen den Configuration-Service zu erreichen. Erst wenn man eine maximale Anzahl an Versuchen erreicht, schlägt der Start fehl.

Eine Alternative zu dieser Lösung ist es, nichts weiter zu tun: Sollte ein Service aufgrund von fehlenden Infrastruk-turdiensten nicht starten, wird K8s nach einer gewissen Zeit den Dienst neu starten, da er nicht antwortet. Das passiert so lange, bis alle Dienste die benötigte Infrastruk-tur vorfinden und sauber starten. Das klingt zunächst merkwürdig, aber das System heilt sich quasi allein.

Für Zwitscher haben wir die gesamte Spring-Cloud-Infrastruktur eins zu eins auf K8s portiert. Alternativ dazu kann auch auf Teile der Spring-Cloud-Infrastruk-tur verzichtet und stattdessen die K8s-Infrastruktur ge-nutzt werden. Der Netflix-Eureka-Server kann durch den K8s-DNS-Server ersetzt werden. Der Zuul-Edge-Server lässt sich außerdem durch Ingress von K8s erset-zen, etcd kann als Konfigurationsmechansimus genutzt werden. Es gibt ein Spring-Cloud-Projekt, das die K8s-Bausteine besser integrieren soll, um genau so etwas zu bewerkstelligen. Es befindet sich aktuell in einem sehr frühen Stadium und ist noch nicht für ernsthafte Pro-jekte geeignet.

FazitDa K8s unter dem Dach der Linux Foun dation weiter-entwickelt wird, ist es wahrscheinlich, dass sich damit ein Standard für Clusterorchestrierung etabliert. Die Aufmerksamkeit und die Entwicklungsgeschwindigkeit ist bei K8s schon jetzt sehr hoch. K8s ist produktions-reif, wenngleich auch manche Features wie Auto-Scaling

Listing 7

$ kubectl.sh create -f zwitscher-eureka/k8s-zwitscher-eureka.yml$ kubectl.sh create -f zwitscher-config/k8s-zwitscher-config.yml$ kubectl.sh create -f zwitscher-service/k8s-zwitscher-service.yml...$ kubectl.sh get deployments,pods$ kubectl.sh scale deployment zwitscher-service --replicas=3$ kubectl.sh get deployments,pods

Listing 8

spring: cloud: config: enabled: true failFast: true retry: initialInterval: 1500

maxInterval: 5000 maxAttempts: 5 multiplier: 1.5 discovery: enabled: true serviceId: ZWITSCHER-CONFIG

nur in der Google Cloud verfügbar sind. Das wird sich aber schnell ändern. Wir konnten nicht auf alle span-nenden Features eingehen. Bei Interesse sei auf die K8s-Dokumentation [1] und das Buch von Kelsey Hightower zu K8s verwiesen [11], das demnächst erscheinen wird.

Dr. Josef Adersberger ist technischer Geschäftsführer der QAware GmbH, einem IT-Projekthaus mit Schwerpunkt auf Cloud-native Anwendungen und Softwaresanierung. Er hält seit mehr als zehn Jahren Vorlesungen und publiziert zu Themen des Software-Engi-neerings, aktuell insbesondere zu Cloud Computing.

Mario-Leander Reimer ist Cheftechnologe bei der QAware. Er ist Spezialist für den Entwurf und die Umsetzung von komplexen Sys-tem- und Softwarearchitekturen auf Basis von Open-Source-Tech-nologien. Als Mitglied im Java Community Process (JCP) ist sein Ziel, die Java-Plattform weiter zu verbessern und praxistaugliche Spezifikationen zu entwickeln.

Links & Literatur

[1] Kubernetes-Dokumentation: http://kubernetes.io/docs

[2] Cloud Native Computing Foundation: https://cncf.io

[3] Prometheus: https://prometheus.io

[4] Weave Scope: https://github.com/weaveworks/scope

[5] sysdig: http://www.sysdig.org

[6] Helm by Deis: https://github.com/helm/helm

[7] Kubernets in der GCE: http://kubernetes.io/v1.1/docs/getting-started-guides/gce.html

[8] Kubernetes mit Vagrant: http://kubernetes.io/v1.1/docs/getting-started-guides/vagrant.html

[9] Alpine Linux Image: https://github.com/Trunkplatform/docker-alpine-node-kubernetes

[10] Cloud Native Zwitscher Showcase: https://github.com/qaware/cloud-native-zwitscher

[11] Kelsey Hightower: „Kubernetes: Up and Running“, O’Reilly, 2015

[12] Kubernetes Secrets: http://kubernetes.io/docs/user-guide/secrets/

[13] Fabric8 Kubeflix: https://github.com/fabric8io/kubeflix

QAware [email protected]

Aschauer Straße 3281549 MünchenTel.: +49 (0) 89 23 23 15 - 0

Rheinstraße 4D55116 MainzTel.: +49 (0) 6131 215 69 - 0