Kolumne: Docker rockt Java

Docker für Java-Entwickler

Peter Roßbach
Docker für Java-Entwickler

Infrastruktur macht die Ausführung unserer Software erst möglich. Der Markt erwartet von uns eine schnellere Lieferung von Änderungen, eine höhere Qualität und mehr Flexibilität im Betrieb. Beim Einsatz von Java als Basis unserer Anwendungen haben wir oft mit der fehlenden Einheitlichkeit unserer Produktions-, Test- und Entwicklungsumgebungen zu kämpfen. Der Anspruch „… runs anywhere“ hat leider in der Praxis seine Tücken. Zum Produkt gehören eben nicht nur das Java-Programm, sondern eine Vielzahl weiterer Infrastrukturkomponenten.

Da es eine enorme Flut von Veröffentlichungen zum Thema Docker, neuen Werkzeugen, Projekten, Ideen und Meinungen gibt, fällt die Auswahl nicht leicht. Wir wollen mit diesem Artikel starten und regelmäßig über das Thema Docker berichten. Seht uns die eine oder andere Unstimmigkeit mit der Realität also nach. Schreibt selbst einen Beitrag und schickt uns Wünsche für wichtige Themen. Wer Docker noch nicht probiert hat, kann dies einfach auf der Seite https://www.docker.com/tryit/ kurz nachholen. Eine Fülle an Büchern zum Thema ist angekündigt, und das Docker Book von James Turnbull liefert gute Starthilfe. In dieser Kolumne berichten wir über die Neuigkeiten und aktuellen Möglichkeiten mit Docker.

Docker meets Java

Neue Kollegen einzubinden und alte Projekte schneller änderbar zu bekommen, sind zeitraubende alltägliche Herausforderungen. Unsere Java-Software-Artefakte sind enorm portabel, die Infrastruktur indes leider nur sehr selten. Seit dem Jahr 2014 hat das Projekt Docker viel Aufmerksamkeit erfahren. Die Software wird einfach als Ganzes inklusive der Ablaufumgebung in Container verpackt und mithilfe der Docker-Registry bereitgestellt. Software kann nun so einfach wie LEGO zusammengesteckt und nutzbar gemacht werden. Docker-Container laufen auf der Basis der Linux-Kernel-Virtualisierung und eines Union-Filesystems. Das schont die Ressourcen enorm und sorgt für ausgezeichnete Performance. Die eigene Software läuft isoliert ohne Änderungen auf dem eigenen Notebook, Data Center oder in einer Cloud. Vorsicht: Wer Docker einmal probiert hat, will mehr davon!

Auf dem Docker-Hub stehen unzählige fertige Images für uns Java-Entwickler bereit. Der erste Schritt zur Anbindung von Datenbanken, Webservern oder Tools sollte Docker Hub sein. Für Java gibt es ein Trusted Build von Docker Inc., dem Initiator hinter Docker. Natürlich gibt es Images für die zahlreichen Java-Tools, Java-EE- und Webcontainer. Durch die Einschränkungen der Lizenzierung von Oracle Java gibt es leider aktuell keine Möglichkeit, öffentlich auf dieser Basis Java-Projekte bereitzustellen. Die Installation von Docker auf dem eigenen Mac oder der eigenen Windows-Maschine gelingt in der Regel durch die Installation mit boot2docker. Wer es direkt auf einer aktuellen Linux-Distribution mit einem Kernel >3.8 probieren möchte, benötigt nur die folgenden Zeilen:

$ curl -sSL https://get.docker.com/ | sh

$ docker info

Es stehen jede Menge verschiedener OpenJDK-basierter Java-Versionen 6, 7 und 8 bereit. Das offizielle OpenJDK-Image basiert auf dem aktuellen Debian 8 (Jessie). Ein öffentliches Oracle-Docker-Image kann es zurzeit wegen lizenzrechtlicher Bestimmungen leider nicht geben. Die Ausführung verschiedener Java-Versionen, des JDK oder JRE ist einfach, flexibel und transportabel möglich (Listing 1).

Listing 1: Docker-Java-Container ausführen

$ docker run --rm java:8 java -version
Unable to find image 'java:8' locally
java:8: The image you are pulling has been verified
...
openjdk version "1.8.0_40-internal"
OpenJDK Runtime Environment (build 1.8.0_40-internal-b09)
OpenJDK 64-Bit Server VM (build 25.40-b13, mixed mode)
$ docker run --rm java:7 java -version
java version "1.7.0_65"
OpenJDK Runtime Environment (IcedTea 2.5.3) (7u71-2.5.3-2)
OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)
$ docker images | grep java
java  8 aec8201c9d63 2 weeks ago 590.6 MB
java  7 2853fadead12 2 weeks ago 536.2 MB
$ docker run -it --rm java:8 /bin/bash -c "cat /etc/*-release"
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
...

Ein paar Shell-Aliasse lassen die länglichen Docker-Kommandos schrumpfen. Unser aktuelles Verzeichnis soll im Container bereitstehen und der Java-Compiler oder die Java-Runtime direkt ausgeführt werden. Die Isolierung der Prozesse in separate Container hat einen kleinen Preis (Listing 2). Dafür können wir nun unsere Anwendung schnell und ohne viel Aufwand auch auf der Basis verschiedener Java-Versionen testen.

Listing 2: Shell-Alias zur vereinfachten Ausführung der Java-Container

$ alias dj7='docker run --rm \
 -v "$(pwd)":/app -w /app java:7 java'
$ alias dj7c='docker run --rm \
 -v "$(pwd)":/app -w /app java:7 javac'
$ cat >Main.java <

Das Erzeugen eines eigenen Images kann mithilfe eines Dockerfiles erfolgen. Aus der Beschreibung wird das Image lokal erzeugt und kann dann auf den eigenen Hub-Account oder eine private Docker-Registry geladen werden. Von dort kann man das Main-Programm nun auf jedem Docker-fähigen Host laden und ausführen.

Wer mehr Freiheit, Kontrolle, Sicherheit, auf dem Hub nicht verfügbare Versionen oder Java-Distributionen benötigt, muss die Basis selbst erzeugen. Das eigene Programm kann natürlich auf der Basis eines JRE auf dem eigenen Hub-Account bereitgestellt werden. Dazu ist es notwendig, einen entsprechenden Account auf dem Hub zu registrieren. Mithilfe eines Dockerfile beschreibt man die Artefakte des neuen Images. Die Basis des Images ist hier java:8-jre. Mit jedem Befehl im Dockerfile wird ein neuer „Filesystem-Layer“ erzeugt. Jedes Image besteht also aus aufeinander aufbauenden Schichten von Dateien und Verzeichnissen, die übereinander angeordnet sind. Damit wird erreicht, dass verschiedene Docker-Container sich Layer teilen können. Alle geteilten Layer sind read-only. Das beschleunigt das Laden der Images und spart Systemressourcen bei der Ausführung.

Die Layer des Images können einfach zum Hub hochgeladen werden. Auch dort werden nur die Schichten transportiert, die noch nicht auf dem Hub vorhanden sind (Listing 3). Der Hub bietet die Möglichkeit der automatischen Bereitstellung von Docker-Images bei Änderungen von Projekten auf GitHub oder Bitbucket. Wer auf solche Aktualisierungen reagieren möchte, kann dies durch eine Registrierung eines WebHooks erreichen.

Listing 3: Veröffentlichung der eigenen Java-Anwendung auf Docker Hub

$ cd app
$ cat >Dockerfile <<EOF
FROM java:8-jre
COPY Main.class /app
WORKDIR /app
CMD ["java", "Main"]
EOF
$ docker build -t "infrabricks/jm-ex-main" .
$ docker run --rm infrabricks/jm-ex-main
$ docker login \
 --username infrabricks \
 --email infrabricks@bee42.com \
 --password streng-geheim
$ docker push infrabricks/jm-ex-main

Maven-Toolcontainer

Alles immer zu Fuß und mit den Mitteln der Shell zu erreichen, ist natürlich für die Implementierung von Java-Anwendungen nicht sinnvoll. Dafür haben wir in den letzten zwanzig Jahren zuverlässige Build-Tools entwickelt. Ob nun Maven, Ant, Gradle oder Buildr genutzt wird, ist der persönlichen Vorliebe überlassen. Die Bereitstellung der meisten Java-Anwendungen ist einfach, da als Voraussetzung meist nur eine bestimmte Java-Edition vorgeschrieben ist. Das Maven-Dockerfile zeigt, wie einfach die Bereitstellung eines Maven-Docker-Toolcontainers ist (Listing 4). Die lokale Bereitstellung erfordert übersichtlichen Aufwand (Listing 5).

Listing 4: Maven-Dockerfile

FROM java:8
MAINTAINER Peter Rossbach <peter.rossbach@bee42.com> @PRossbach
ENV MAVEN_VERSION 3.2.3
RUN curl -sSL http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz | tar xzf - -C /usr/share \
 && mv /usr/share/apache-maven-$MAVEN_VERSION /usr/share/maven \
 && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
ENV MAVEN_HOME /usr/share/maven
ENTRYPOINT ["mvn"]
CMD ["--version"]

Listing 5: Bereitstellung von Maven als Docker-Container

$ docker run --rm infrabricks/jm-maven3
Apache Maven 3.2.3 (33f8c3e1027c3ddde99d3cdebad2656a31e8fdf4; 2014-08-11T20:58:10+00:00)
Maven home: /usr/share/maven
Java version: 1.8.0_40-internal, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.16.7-tinycore64", arch: "amd64", family: "unix"

Zur Nutzung des Maven-Toolcontainers müssen das aktuelle Verzeichnis und die lokale Konfiguration für jeden Aufruf bereitgestellt werden. Dies erreicht man durch das Erzeugen der entsprechenden Shell-Aliasse, die in der Datei ‚~/.bash_alias‘ gespeichert werden können. Mit dem Alias dmvn kann nun eine wirkliche abgeschottete Umgebung eines Docker-Containers erfolgen. Das Erzeugen eines Projekts ist absolut wiederholbar und getrennt von anderen Installationen (Listing 6).

Listing 6: Maven im Docker-Toolcontainer

$ alias dmvn="docker run --rm \
  -v 'pwd':/app -w /app -v ${HOME}/.m2:/root/.m2 \
  infrabricks/jm-maven3"
$ dmvn archetype:generate \
 -DgroupId="io.infrabricks.example" \
 -DartifactId="my-app" \
 -DarchetypeArtifactId="maven-archetype-quickstart" \
 -DinteractiveMode="false"
...
$ cd my-app
$ dmvn clean package
...
$ alias dj="docker run --rm \
 -v 'pwd':/app -w /app \
 --entrypoint=java infrabricks/jm-maven3"
$ dj -cp target/my-app-1.0-SNAPSHOT.jar io.infrabricks.example.App
Hello World!
Abb. 1: Docker und Java

Abb. 1: Docker und Java

In einer der nächsten Ausgaben werden wir stärker auf das Thema Maven und Docker eingehen. Wer möchte, sollte sich die beiden folgenden Maven-Docker-Plug-ins ansehen: https://github.com/rhuss/docker-maven-plugin, https://github.com/wouterd/docker-maven-plugin.

Mehr geht immer …

Häufig sind die Bedürfnisse für die Bereitstellung von Software sehr individuell. Für Java-Entwickler ist die Ablaufumgebung meist während der Implementierung nur für das Testen wirklich relevant. Allerdings ist die Übertragbarkeit auf andere Arbeitsplätze, Test- und Kundenumgebungen aufwändig und stellt sich zunehmend als Hindernis heraus. Die Backends, das Netzwerk oder die eingesetzten Betriebssysteme und Versionen variieren. Hier kann Docker einen wertvollen Beitrag zur Harmonisierung der Tools und Umgebungen liefern. Wir können als Entwickler nun sehr leicht die Backends in Container verpacken und in verschiedenen Konfigurationen zusammenfügen. Die Konfiguration der Software erfolgt im einfachsten Fall über Unix-Umgebungsvariablen oder eleganter über einen zentralen Discovery-Service. Im meinem Blog-Post „Docker Microservice-Basis mit Apache Tomcat implementieren“ finden sich dazu mehr Anregungen und zwar hier und hier.

Fazit

Jeder Entwickler wird schnell merken, dass Docker in der Kombination mit der Shell mehr Potenzial hat als erwartet. Neue und bestehende Technologien einzusetzen und bereitzustellen war noch nie so einfach und schnell möglich. Es geht bei der Herstellung und Bereitstellung eines Service immer mehr um konsequente Automatisierung der gesamten Infrastruktur, die der Entwickler und Administrator mitgestaltet, betreibt und versteht. Nur einen Teil zur Implementierung beizutragen, ist zu wenig. Die Organisationen werden in naher Zukunft die Ideen der DevOps-Bewegung adaptieren müssen, sonst drohen große Wettbewerbsnachteile.

Das Prinzip von Unix durch Kombination einfacher unabhängiger Teile und Wiederverwendung etwas zu erreichen, ist auch im 21. Jahrhundert enorm angesagt. Große Plattformen und umfassende Werkzeuge von einem Anbieter sind meist verwirrend und zeitlich nur sehr begrenzt hilfreich. Gerade die Ideen rund um das Thema Microservices und Resilient-Patterns machen klarer, welchen Lösungen die Zukunft gehört. Die Bereitstellung nützlicher Software, die austauschbar ist und aus unabhängigen Teilen besteht, ist von enormem Wert. Das entstehende Docker-Ökosystem hilft hier in allen Belangen, von diesem Nutzen schnell zu profitieren. Auf der DockerCon in Amsterdam im Dezember 2014 wurden die Projekte Docker Machine, Docker Swarm und Docker Compose für die Orchestrierung von Infrastruktur intensiv diskutiert. Aktuell gibt es viele Ideen im Bereich Docker-Networking, eine nachhaltige Verbesserung zu erreichen. Jeder von uns soll seine Software einfach und direkt auf einer Cloud oder im Kunden-Datacenter auf vielen Maschinen ausrollen und betreiben können.

Mehr zum Thema:

Docker-Tools im Vergleich: Welches Container-Tool passt zu mir?

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

Schreibe einen Kommentar

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