Kolumne

Docker rockt Java: Docker-Orchestration und -Entwicklung leicht gemacht

Peter Roßbach
docker-fuer-java

Das Release von Docker 1.12 bietet direkt die Orchestrierung von Containern an. Mit Docker für Mac und Windows verbessert sich die Unterstützung für die Entwickler. Die Betaversion von Docker für AWS und Azure vereinfacht die Erstellung einer Produktion in der Cloud. Als besonderes Bonbon wird uns demnächst ein Marktplatz für Docker-Images in Aussicht gestellt. Wahrlich ein gigantischer Fortschritt, der den professionellen Einsatz von Docker erleichtert und die anhaltende Produktivität der Docker-Community erneut unter Beweis stellt.

Auf der DockerCon 2016 sind der Community viele Ergebnisse des letzten halben Jahres präsentiert worden. Für die Entwickler ist es mit Docker für Mac und Windows nun deutlich leichter geworden, auf der Basis von Docker wirklich zu implementieren. Die Bereitstellung aller möglichen Docker-Container für die Entwicklung ist nun wirklich einfach. Mit der Integration via xhyve auf dem Mac und mit Hyper-V für Windows schafft Docker nun eine fast vollständige Hostintegration. Keine Probleme mehr, Dateien auf dem Mac oder mit Windows zu ändern und diese Veränderung auch direkt mit einer Reaktion im Container zu verknüpfen. Endlich! Die gesamten Build- und Auto-Deployment-Werkzeuge greifen nun voll. Debugging ist direkt aus der Entwicklungsumgebung mit Software im Container möglich, da nun eine Netzwerkunterstützung des Hosts existiert. Sogar die direkte Integration eines VPN-Tunnels im Container ist gelöst. Die Zusammenarbeit der Unikernel-, Apple- und Microsoft-Entwickler trägt erste reife Früchte. Die Integration von Kitematic und das Autoupdate werden ebenfalls unterstützt. Eine einfache Veränderung der Konfiguration und des Managements ist inklusive.

Mit Docker für AWS und Azure wird es möglich, die eigenen Ergebnisse direkt auch in Produktion zu stellen. Um diesen Schritt real werden zu lassen, gibt es zwei neue Beschreibungsformate. Mit dem DAB-Format wird eine Menge von Services samt Storage und Netzwerke beschrieben. Aktuell kann dieses Format mit dem Werkzeug Docker Compose in der Version 1.8 halbwegs erzeugt werden. Mit dem Stack-Format sollen dann viele Services samt Infrastruktur für die Cloud beschrieben und installierbar gemacht werden.

In naher Zukunft werden wir unsere Software und Systeme dann im Docker Store anbieten und hoffentlich auch vermarkten können. Warum sollen wir diese Möglichkeit auch nicht für Serversoftware endlich hinbekommen? In den diversen Stores für Mobile- und Desktopcomputer hat diese Entwicklung ebenfalls gute Resultate gezeigt.

DevOps Docker Camp 2017

Das neue DevOps Docker Camp – mit Erkan Yanar

Lernen Sie die Konzepte von Docker und die darauf aufbauende Infrastrukturen umfassend kennen. Bauen Sie Schritt für Schritt eine eigene Infrastruktur für und mit Docker auf!

Docker-News

  1. Docker 1.12
    • Integration von SwarmKit – Orchestration, Sicherheit und Clustering-Support
    • Erweiterungen des Dockerfiles (Shell, Healthcheck)
    • Verbesserung des Netzwerkstacks (Verschlüsselung)
    • Plug-in Manager
    • Experimentaler Support von MACvlan und IPvlan
    • Daemon Reload ohne Stoppen der Container
  2. Docker für Mac und Windows
    • Die Version 1.0 ist nun mit Docker 1.12 verfügbar
    • Unterstützung der nativen Virtualisierung von Mac und Windows via xhyve und Hyper-V
    • Autoupdate (Stable und Development)
    • Komplete Integration des Hostfilesystems und Netzwerks inkl. VPN-Support
    • Neue Docker-Projekte zur Unterstützung der „Native Virtualisation“
      • HyperKit
      • DataKit
      • VPNKit
  3. Docker für AWS und Azure (Beta)
  4. Docker Store
  5. Docker Cast und YouTube-Channel
  6. Aktualisierung für die Werkzeuge Docker Machine und Docker Compose sind ebenfalls erfolgt.

Einfach ein Docker-Cluster bilden

Wie es sich seit Anfang des Jahres in der Sourcecode-Basis der Docker-Projekte abzeichnete und durch zahlreiche Tweets und Blogartikel vermutet wurde, ist nun die direkte Orchestrierung von Containerbestandteilen der Docker Engine 1.12 verfügbar. Bisher war ein Containercluster nur mit zusätzlichen Projekten wie Kubernetes, Mesos oder Swarm möglich. So richtig einfach oder elegant war dieser zusätzliche Aufwand für die meisten DevOps-Entwickler nicht. Profis fanden die Reduktionen der Komplexität schon attraktiv, aber für die meisten Entwickler und Administratoren war der Zugang zu kompliziert. Mit der Integration des SwarmKits in die Docker Engine ist es nun wirklich einfach und nachvollziehbar. Auf der letzten DevOpsCon 2016 in Berlin wurde schon demonstriert, wie elegant und einfach das SwarmKit die Aufgabe der Orchestrierung bereitstellt. Die direkte Integration des Swarmkits in die Docker Engine verschafft uns nun einen intuitiven Zugang zur maschinenübergreifenden Containerorchestrierung (Listing 1). Im Beispiel werden einfach drei VirtualBox-Maschinen erzeugt. Dann wird auf der ersten Maschine swarm_node_1 ein Swarm-Manager erzeugt. Mit dem entsprechende Token werden zwei Worker swarm_node_2 und swarm_node_3 mit dem Manager auf dem swarm_node_1 verbunden. Fertig ist der komplette Cluster samt Netzwerk, vollständiger Verschlüsselung und Auto-Failover-Management. Fast beliebig skalierter ist es auch noch. Der Cluster von Chanwit Kaewkasi lief mit 2 384 Knoten einige Tage in der Cloud von Scaleway stabil.

# (0) Install docker 1.12 and docker-machine 0.8 at your client
# (1) Create Docker Machines
$ docker-machine create -d virtualbox swarm_node_1
$ docker-machine create -d virtualbox swarm_node_2
$ docker-machine create -d virtualbox swarm_node_3
# (2) Init Swarm Manager
$ eval $(docker-machine env swarm_node_1)
$ docker swarm init \
  --advertise-addr $(docker-machine ip swarm_node_1) \
  --listen-addr $(docker-machine ip swarm_node_1):2377
$ TOKEN=$(docker swarm join-token -q worker)
# (3) Attach Workers to the Swarm
$ eval $(docker-machine env swarm_node_2)
$ docker swarm join \
  --token $TOKEN \
  $(docker-machine ip swarm_node_1):2377
$ eval $(docker-machine env swarm_node_3)
$ docker swarm join \
  --token $TOKEN \
  $(docker-machine ip swarm_node_1):2377

Der Docker Swarm kennt zwei verschiedene Rollen, die auch im laufenden Betrieb verändert werden können: Manager und Lead-Manager (Abb. 1). Die Manager koordinieren die Struktur des gesamten Clusters. Zu jedem Zeitpunkt wird der Zustand auf allen Managern gespeichert. Der Lead-Manager entscheidet, welche Aufgaben existieren und auf welchen Workern umgesetzt werden. Dabei ist die gesamte Kommunikation verschlüsselt. Die Manager bilden einen eigenen CA und stellen die entsprechenden Zertifikate aus. Die Zertifikate werden im laufenden Betrieb automatisch ausgetauscht. Die Vertraulichkeit des Zustands und der Kommunikation ist also hoch. Für den Eintritt eines neuen Knotens im Cluster wird ein Token als Geheimnis benötigt (Listing 1). Fallen Clusterknoten oder Container eines Service aus, greift das Failover-Management (Docker 1.12 Swarm Mode Deep Dive Part 1 & Part 2). Wenn tatsächlich der Lead-Manager ausfällt, wird auf der Basis eines Quorums ein neuer Leader gewählt. Die Steuerung des Docker-Clients kann über jeden Manager im Cluster erfolgen. Der Docker-Swarm-Cluster braucht also keinen separaten Zustandsspeicher, wie es Kubernetes mit etcd, Mesos mit ZooKeeper oder der Swarm-Proxy mit verschiedenen Service-Discovery-Lösungen benötigt. Die komplette Management-Control-Plane muss für die Docker-Swarm-Cluster nicht mehr installiert und gepflegt werden. Alles ist in der Docker Engine 1.12 vorhanden. Hier hat die Docker-Community für ein schwieriges technisches Problem eine elegante und schmale Lösung bereitgestellt. Die Ergänzung der automatischen Sicherheit der Kommunikation ist außerdem gelungen.

Abb. 1: Kommunikation der verschiedenen Komponenten in einem Docker-Cluster

Abb. 1: Kommunikation der verschiedenen Komponenten in einem Docker-Cluster

Services auf einem Docker-Cluster anbieten

Der Docker-Swarm-Cluster kommuniziert über einen der Managementknoten. Ein Übersicht über die Rolle aller Maschinen im Cluster wird mit dem Befehl docker node ls geliefert. Nun können die verteilten Services gestartet werden. Der Manager übernimmt die Aufgabe, die Container des Service auf die Knoten zu verteilen. Mit dem Befehl docker service tasks können die Aufgaben, die gerade verarbeitet werden, angezeigt werden (Abb. 2). Skalierung und Redeployment von neuen Versionen sind inklusive. Es können alle Container ausgetauschten werden oder es kann in einer bestimmten Frequenz und Anzahl die Umstellung erfolgen (Abb. 3). Natürlich ist ein Neustart, das Stoppen oder Löschen des Service möglich (Listing 2). Wenn ein Container eines Service oder gar ein kompletter Knoten nicht mehr antwortet, werden die Container auf die verbleibenden Knoten erneut verteilt und neu gestartet. Jeder Service bekommt eine eigene IP-Adresse zugeordnet. Hiermit können alle anderen Container den Service erreichen. Es wird ein automatisches Load Balancing unterstützt. Die Services sind via Docker-DNS abfragbar. Wenn ein Service seine Ports publiziert, ist der Port anschließend auf allen Knoten des Clusters direkt verfügbar, unabhängig davon, ob ein Container des Service auf dem Knoten gestartet ist. Der Netzwerkstack jedes Knotens erledigt das Routing und Load Balacing. Ein externer Load Balancer muss also den Traffic auf alle Knoten verteilen und nicht mehr die Location der einzelnen Container im Cluster verfolgen.

Als zweite Strategie für die Verteilung eines Service gibt es die Möglichkeit, einen Container exklusive auf allen Knoten bereitzustellen. Kommt ein Node hinzu, wird automatisch vom Scheduler entschieden, den Service dort bereitzustellen. Im Beispiel ist auf allen Knoten der cAdvisor-Container bereitgestellt. Somit ist die Überwachung jedes Knotens einfach gewährleistet (Listing 3). Die Bereitstellung von Storage oder Netzwerken über den Cluster erfolgt automatisch. Der neue Plug-in-Manager stellt noch nicht das evtl. fehlende Plug-in auf einem Knoten bereit, aber bis zum nächsten Release könnte es soweit sein. Netzwerke verschwinden auf den Knoten wieder, wenn kein Service sie mehr nutzt. Nicht alle RUN-Optionen sind für Container eines Service verfügbar. Aber neben Einschränkungen von CPU und Memory, dem Bereitstellen von Umgebungsvariablen und Labeln sowie der Wahl der Netzwerke ist das Bereitstellen von Volumes vorhanden. Damit eine Menge kooperierender Services auf einen Cluster übertragen werden kann, existiert eine Konfigurationsdatei im DAB-Format.

Abb. 2: Swarmkit Domain Model

Abb. 2: Swarmkit Domain Model

Abb. 3: Verschiedene Docker-Orchestration-Module in Aktion

Abb. 3: Verschiedene Docker-Orchestration-Module in Aktion

$ eval $(docker-machine env swarm_node_1)
$ docker node ls
$ docker service create --name whoami \
  —publish 8081:80/tcp emilevauge/whoami
$ docker service tasks whoami
$ curl $(docker-machine ip swarm_node_1):8081
$ curl $(docker-machine ip swarm_node_2):8081
$ curl $(docker-machine ip swarm_node_3):8081
$ docker service scale whoami=4
# Repeat access and see which container generate the answers
# Start a new service and deploy next version...
$ docker service create --replicas 8 --name micro_service \
  --network mynet --publish 80:80/tcp service:v1.0
$ sleep 10
$ docker service update --image service:v2.0 \
  --update-delay 5s --update-parallelism 2 micro_service
# access service and see at which time new version is accessible
$ eval $(docker-machine env swarm_node_1)
$ docker service create --name cadvisor --mode global \
--mount type=bind,source=/,target=/rootfs/,writable=false \
--mount type=bind,source=/var/run/,target=/var/run/ \
--mount type=bind,source=/sys/,target=/sys/,writable=false \
--mount type=bind,source=/var/lib/docker/,target=/var/lib/docker/,writable=false \
  --publish 8080:8080 \
  google/cadvisor:latest

Weitere Neuerungen im Release 1.12

Neben den vielen Bugfixes und kleinen Verbesserungen gibt es ein paar bedeutende Erweiterungen. Die Docker Engine kann nun mit der Option dockerd —live-restore gestartet werden. Damit wird es möglich, dass Container einen Neustart der Engine überstehen. Im Dockerfile kann die Shell vor der Ausführung eines RUN-Befehls gesetzt werden. Damit können nun neben sh, auch Bash, zsh und PowerShell für Windows-Dialekte im Dockerfile direkt verwendet werden. Die Docker Engine kann nun aktiv den Laufzeitzustand der Prozesse in einem Container prüfen. Der Befehl HEALTHCHECK ermöglicht die Formulierung entsprechender Checks. Wenn dieser Test dreimal hintereinander alle fünf Minuten fehlschlägt, wird der Container als fehlerhaft gekennzeichnet. Ist der Container einem Clusterservice zugeordnet, wird ein Restart des fehlerhaften Containers durchgeführt (Listing 4). Der neue Plug-in-Manager erlaubt es nun, die Erweiterung der Docker Engine direkt zu installieren und zu verwalten (Listing 5).

FROM xxx
...
HEALTHCHECK --interval=5m --timeout=3s \
  --retries=3 CMD curl –f http://localhost:8080/health || exit 1
$ docker plugin install tiborvass/no-remove
$ docker plugin enable no-remove
$ docker plugin disable no-remove

Fazit

Noch fällt es etwas schwer, die einfache Lösung von Docker-Swarm-Cluster im Release 1.12 mit den bisherigen Orchestrierungslösungen direkt zu vergleichen. Sicherlich können Kubernetes und Mesos mit einigen interessanten Eigenschaften punkten. Aber in den Punkten Einfachheit, Verständlichkeit, Verfügbarkeit und Sicherheit wird es schwer werden, Docker Swarm von Platz 1 zu verdrängen. Die integrierte Service-Discovery, das einfache publizieren von Serviceports, Container-Load-Balancing und die Bereitstellung von Netzwerken und Volumes sind weitere Eigenschaften, die überzeugen. Es bleibt sehr spannend, die ersten produktiven Einsatzberichte zu lesen.

Schön wäre es, wenn in einem der nächsten Releases ein Scheduling von Jobs oder ein Function-Gateway wie Amazon Lambda verfügbar wäre. Noch ist der Einsatz des Clusters auf Netzwerkabschnitte begrenzt. Eine echte WAN-Fähigkeit oder ein Swarm-Cluster in verschiedenen Netzwerkzonen wird noch nicht unterstützt. Der Einsatz wird gerade hitzig diskutiert, und in den kommenden Monaten wird es weitere Neuigkeiten geben. Wer mit Docker gerade beginnt und erste Informationen benötigt, findet diese in dem frischen und aktualisierten Docker-Buch von Adrian Mouat „Docker: Software entwickeln und deployen mit Containern“, zu dessen Übersetzung ich etwas beitragen durfte.

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
  1. Uwe2016-12-05 14:40:57

    Hallo Peter,

    vielen Dank für die schöne Zusammenfassung! Was ich mich jetzt allerdings frage ist, ob über das integrierte Swarm nun auch die komplette Remote API zur Verfügung gestellt wird ? Kann ich mit 'docker service logs ' alle Logs von allen Knoten bekommen? Oder muss ich dies weiterhin bei jedem Docker-Daemon lokal abfragen?

    Viele Grüße
    Uwe

  2. Christian Fromme2016-12-05 18:49:40

    Hallo Herr Roßbach,

    vielen Dank für den interessanten Artikel.

    Eine Frage: Wie funktioniert die Discovery ohne etcd, Consul oder Zookeeper? Über Docker Hub? Das wäre ja dann erstmal nur für Anwendungen mit ständigem Internet-Zugriff auf Docker Hub brauchbar.

    (Siehe auch https://docs.docker.com/swarm/provision-with-machine/ "These command rely on Docker Swarm’s hosted discovery service, Docker Hub. If Docker Hub or your network is having issues, these commands may fail.")

    Grüße,
    Christian Fromme

  3. Christian Fromme2016-12-07 13:26:08

    Kurzer Nachtrag:

    Um mir die Frage zu beantworten, habe ich es schnell mal ausprobiert. Ja, Docker braucht ab 1.12 tatsächlich keine externen Dienste für die Discovery. Auch nicht Docker Hub.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.