Kolumne

Docker rockt Java: Mit Kubernetes in der Entwicklung starten

Peter Roßbach

Die Plattform Kubernetes bietet ein leistungsfähiges Container-Orchestration-System, das von Google und Red Hat gemeinsam entwickelt wird. Kubernetes zielt darauf ab, bessere Möglichkeiten für die Verwaltung verteilter Anwendungen in einer dynamischen Infrastruktur zu schaffen. Docker-Experte und JAX Speaker Peter Roßbach zeigt in dieser Kolumne, welche neuen Herausforderungen sich dabei stellen, die eigene Software betriebsfähig zu liefern.

Kubernetes erzeugt, skaliert und verbindet Gruppen von Containern in einem Cluster von Maschinen. Aktuell unterstützt es Docker- oder CoreOS-Rocket-Container. Eine Gruppe dieser Container nennt sich Pod. Die Container eines Pods teilen sich Konfigurationen, ein Netzwerkinterface und Volumes. Auf jeder Maschine eines Clusters können diese Pods durch einen zentralen Manager gestartet werden (Abb. 1). Außerdem lassen sich die verschiedenen Pods zu einem Service zusammenfassen. Dieser Service bekommt dabei einen eigenen Port und eine eigene IP-Adresse. Mit diesem einfachen Ansatz können andere Pods bereits auf alle Prozesse dieses Service zugreifen. Die Last wird dabei automatisch auf alle Pods eines Service verteilt. Veränderungen der Anzahl der Pods lassen sich so transparent für die Clients berücksichtigen. In der Realität klappt dies nur problemlos, wenn die neuen Pods ein kompatibles API unterstützen und die Clients entsprechende Recovery-Routinen für Netzwerkverbindungen implementiert haben. Um den Anschluss an die externe Welt mit entsprechenden Load Balancern muss man sich allerdings meist selbst kümmern.

Wer Kubernetes in OpenShift oder in der Google Cloud Engine einsetzt, bekommt schon eine leistungsfähige Load-Balancer-Integration. In Kubernetes 1.1 gibt es die Ingress-Load-Balancer-Abstraktion zusätzlich, die weitere Routing-Optionen definiert. Eine weitere wichtige Neuerung ist die Möglichkeit, Autoscaling von Pods auf der Basis des CPU-Verbrauchs zu konfigurieren. Im Detail sind die Konzepte und Lösungen komplex und bieten vielseitige Verwendungsmöglichkeiten. Der Einsatz von Kubernetes erfordert die Bereitstellung einer komplexen Systemumgebung für den Betrieb von vielen Anwendungen. Besonders gut geeignet ist Kubernetes sicherlich für die Entwicklung von Microservices.

Abb. 1: Auf jeder Maschine eines Clusters können die Pods durch einen zentralen Manager gestartet werden

Die Anzahl von Angeboten, die Kubernetes in der Cloud oder On Premise bereitstellen, überschlägt sich in den letzten Monaten. Beschreibungen der verschiedenen Varianten und entsprechende Beispiele zur Installation liefert das Kubernetes-Projekt. Auch vielversprechende Ansätze mit Google Cloud Engine, Azure, Vagrant, CoreOS, OpenStack, Mesos, Docker-Swarm und Docker-Compose stehen zur Verfügung. Weitere Tutorials lassen sich in diversen Blogs und konkreten Projekten auf GitHub finden [1]. Die Auswahl ist allerdings schwierig.

Für einen ersten Test und die Entwicklung reicht allerdings meist eine Installation auf nur einer Maschine. Problematisch sind die Bereitstellung eines entsprechenden Netzwerks, die Vergabe von IPs und die externe Erreichbarkeit. Bevor die Entscheidung für einen solchen Aufwand getroffen werden kann, wäre ein einfacher Test sinnvoll. Der Ansatz in diesem Artikel erzeugt eine Kubernetes-Installation auf nur einer Maschine auf der Basis einer Docker-Compose-Beschreibung und weniger Shell-Skripte [2] (Listing 1).

In wenigen Schritten Container orchestrieren
Als erster Schritt wird eine lokale Docker-Maschine erzeugt. Das Kubernetes-Projekt stellt dafür ein Docker-Image zur Installation bereit. Die einzelnen Services benötigen nur noch einen Zugriff auf ETCD als Key-Value-Datenbank. Mit dem Kommando hyperkube lassen sich die verschiedenen Services konfigurieren und starten (Listing 2). Das Kommando kubelet kann beliebige Kubernetes-Manifeste im Verzeichnis /etc/kubernetes/manifests starten. Mit diesem Trick wird die Kubernetes Control Plane aus den Services-APIs, Scheduler und Manager bereitgestellt (Abb. 2). Der API-Service ist ein CRUD-REST-Service, der seine Daten in ETCD speichert. Der Scheduler entscheidet, welche nicht zugeordneten Pods auf welchen Nodes gestartet werden. Der Manager überwacht die Strukturen und entscheidet, welche Aufgaben vorliegen. Damit alle Services auch durch einen DNS-Service erreichbar sind, wird zusätzlich noch ein SkyDNS-Service gestartet. Die entsprechenden Informationen über laufende Services besorgt der Container Kube2Sky vom Kubernetes-API-Service. Der einfache Kube-UI-Service wird als Erweiterung des API gestartet und schafft eine erste Übersicht über einen Kubernetes-Cluster (Abb. 3). Als Netzwerk dient den Pods die lokale Docker Bridge. Erste Experimente, ein Multi-Host-Netzwerk auf Basis von VXLAN und Docker-Swarm zu nutzen, sind auf der DockerCon EU 2015 schon erfolgreich gezeigt worden. Allerdings gibt es noch Probleme mit der Names-Auflösung der Kubelets.

Auf jeder Maschine existiert ein Kubelet, das für die Anbindung an den Docker Daemon sorgt und den Verbrauch der Ressourcen via cAdvisor-API auf dem Port 4194 bereitstellt. Die Bereitstellung der Services und Endpoints im Kubernetes-Cluster wird vom Kube Proxy auf Basis der Konfiguration der IP Tables umgesetzt. Mit dieser Standalone-Installation lassen sich nun alle Konzepte von Kubernetes lokal testen (Listing 3).

$ brew install \
  git docker docker-compose docker-machine kubernetes-cli
$ git clone https://github.com/infrabricks/kubernetes-standalone
$ cd kubernetes-standalone
$ docker-machine create -d virtualbox \
  --virtualbox-memory "2048" \
  --virtualbox-cpu-count "2" kubernetes
$ eval $(docker-machine env kubernetes)
$ export KUBERNETES_MASTER=http://127.0.0.1:8080
$ ./kube-up.sh
$ kubectl cluster-info
Kubernetes master is running at http://127.0.0.1:8080
KubeUI is running at http://127.0.0.1:8080/api/v1/proxy/namespaces/kube-system/services/kube-ui

Abb. 2: Das Kommando „kubelet“ kann beliebige Kubernetes-Manifeste im Verzeichnis „/etc/kubernetes/manifests“ starten; mit diesem Trick wird die Kubernetes Control Plane aus den Services-APIs, Scheduler und Manager bereitgestellt

Abb. 3: Der einfache Kube-UI-Service wird als Erweiterung des API gestartet und schafft eine erste Übersicht über einen Kubernetes-Cluster

etcd:
  image: gcr.io/google_containers/etcd:2.2.1
  net: "host"
  container_name: etcd
  command: ['/usr/local/bin/etcd', '--addr=127.0.0.1:4001', '--bind-addr=0.0.0.0:4001', '--data-dir=/var/etcd/data']
kubelet:
  image: gcr.io/google_containers/hyperkube:v1.1.2
  net: "host"
  privileged: true
  volumes:
    - /:/rootfs:ro
    - /sys:/sys:ro
    - /dev:/dev
    - /var/run/docker.sock:/var/run/docker.sock
    - /var/lib/docker/:/var/lib/docker:ro
    - /var/lib/kubelet/:/var/lib/kubelet:rw
    - /var/run:/var/run:rw
    - ./manifests:/etc/kubernetes/manifests
  command: /hyperkube kubelet --containerized --api_servers=http://127.0.0.1:8080 --v=2 --address=0.0.0.0 --enable_server --hostname_override=127.0.0.1 --config=/etc/kubernetes/manifests --cluster-dns=172.17.0.1 --cluster-domain=cluster.local
proxy:
  image: gcr.io/google_containers/hyperkube:v1.1.2
  net: "host"
  privileged: true
  command: /hyperkube proxy --master=http://127.0.0.1:8080 --v=2
kube2sky:
  image: gcr.io/google_containers/kube2sky:1.11
  net: host
  command: ['--kube_master_url=http://127.0.0.1:8080', '--domain=cluster.local']
skydns:
  image: gcr.io/google_containers/skydns:2015-10-13-8c72f8c
  net: host
  command: ['--machines=http://localhost:4001', '--addr=0.0.0.0:53', '--domain=cluster.local', '-ns-rotate=false']
  environment:
    - SKYDNS_NAMESERVERS="8.8.8.8:53,8.8.4.4:53"
$ kubectl run nginx --image=nginx —port=80
$ kubectl get pods
NAME                   READY     STATUS    RESTARTS   AGE
k8s-master-127.0.0.1   3/3       Running   0          2m
nginx-0ycul            1/1       Running   0          11s

$ kubectl scale --replicas=2 rc/nginx
$ kubectl expose rc nginx --port=80 —external-ip=$(docker-machine ip kubernetes)

Fazit
Kubernetes ist eine mächtige Technologie für die Orchestrierung von Containern. Sie vereinfacht zwar einen komplexen Betrieb von verteilten Anwendungen, aber erschwert noch die Entwicklung. Mit der gezeigten Installationsmethode können Entwickler nun auch beginnen, sich mit der Produktivumgebung vertraut zu machen. Die Voraussetzungen für den Einsatz sind allerdings vorgefertigte Docker-Images. Diese lassen sich mit entsprechenden Dockerfile-Projekten oder für Java-Entwickler mit den verfügbaren Docker-Gradle– oder Maven-Plug-ins erstellen.

Die Integration von Kubernetes in bestehende Load Balancer ist möglich. Es erfordert aber meist eigene Implementierungen. Für HAProxy und nginx gibt es verschiedene Lösungen. Das Projekt Kubernetes hat ein enormes Entwicklungstempo – alle zwei Wochen gibt es ein neues Release. Die Provisionierung von Maschinen und der Basisinfrastruktur ist nicht wirklich Bestandteil des Kubernetes-Projekts. Es gibt noch viel Spielraum für neue Ideen, Erweiterungen und Projekte.

Geschrieben von
Peter Roßbach
Peter Roßbach
Peter Roßbach ist ein Infracoder, Systemarchitekt und Berater vieler Websysteme. Sein besonderes Interesse gilt dem Design und der Entwicklung von komplexen Infrastrukturen. Er ist Apache Tomcat Committer und Apache Member. Mit der bee42 solutions gmbh realisiert er Infrastrukturprodukte und bietet Schulungen auf der Grundlage des Docker-Ökosystems, aktuellen Webtechnologien, NoSQL-Datenbanken und Cloud-Plattformen an.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: