Blockchain

Eine Blockchain mit Java

Eine Blockchain mit Java

Im vorherigen Artikel wurde die prinzipielle Arbeitsweise einer Blockchain allgemein diskutiert. Eine Blockchain mit Java zu implementieren ist prinzipiell nicht sonderlich schwer und wird im Folgenden gezeigt.

Einige Hinweise sind vorab notwendig, um beim Leser keine übertriebenen Erwartungen zu wecken:

  • Diese Java-Klassen alleine stellen natürlich kein funktionierendes verteiltes Datenbanksystem dar. Dazu fehlt das Netz der Server-Knoten.
  • Eine konkrete Validierung der Records, die in einen Block eingestellt wird erfolgt nur rudimentär. Dies ist selbstverständlich eine Anforderung, die aus einer fachlichen Spezifikation entnommen werden muss. Eine Blockchain für Gesundheitsdaten hat komplett andere Regeln als eine für Finanz-Transaktionen.
  • Komplett weggelassen wurde das Thema „Consense Modelle“, also beispielsweise ein „Proove of Work“ wie beim Bitcoin-Mining.

Das Beispielprojekt

Die im Folgenden gezeigten Beispiele sind im GitHub-Account des Autoren abgelegt. Das Projekt ist frei verfügbar und kann für eigene Demonstrationen und Ergänzungen gerne benutzt werden.

Hashing

Zwingend notwendig für die Arbeit einer Blockchain ist die Bestimmung der hochwertigen Hashes. Dieses Problem ist in der Java-Distribution schon lange gelöst, dafür gibt es die Klasse MessageDigest.  Nachdem diese jedoch etwas sperrig in der Benutzung ist, wird das DigestUtil aus dem Apache Commons Codec-Projekt benutzt:

Der Test beweist, dass die Anforderungen an die Hash-Erzeugung erfüllt sind:

  • Unabhängig von der Länge der Eingangsdaten sind alle Hash-Werte gleich lang, nämlich 32 Zeichen.
  • Die Hash-Werte zweier minimal unterschiedlicher Eingangsdaten weisen keinerlei Ähnlichkeiten auf.
  • Der Wertebereich des Hashes ist so groß, dass zufällige Identitäten ausgeschlossen werden können.

 

Der Block

Die Implementierung eines für die Chain geeigneten Blocks ist tatsächlich sehr einfach. Ein Block enthält

  • die Daten, die für ein einfaches Beispiel beliebig sein können
  • den Hashwert des Vorgängers
  • einen eigenen Hashwert
  • einen Zeitstempel

Eine direkte Umsetzung zeigt folgende Klasse:

Eine korrekte Arbeitsweise beweist dieser Unit-Test:

Die Blockchain

Die Blockchain-Implementierung macht folgendes:

    • Die Klasse hält eine Liste von Blöcken
    • Eine add-Methode nimmt hinzuzufügende Daten entgegen. Diese werden exemplarisch validiert und, nach Erfolg, in einen Block umgesetzt. Dieser wird anschließend in der Liste hinzugefügt.
    • Mit Angabe eines Indexes kann ein bestimmter Datensatz wiederum gelesen werden.
    • Ebenso kann eine Liste aller Daten erhalten werden.

Im Endeffekt bildet die verkettete Liste der Blöcke einen Hash-Baum oder Merkle-Tree.

Auch hier zeigt ein Test das korrekte Funktionieren der Implementierung:

Der Versuch eines Angriffs

Wie kann nun ein Angriff auf diese Blockchain erfolgen? Bevor der Versuch eines Angriffs näher erläutert wird ist es aber wichtig, sich bewusst zu machen, dass die Informationen, die in der Chain abgelegt sind, in der Praxis auf vielen Knoten eines verteilten Systems abgelegt sein werden. Das bedeutet damit, dass der Angreifer seine Attacke nicht nur gegen einen Rechner fahren muss, sondern im Endeffekt gegen eine Majorität der Rechner. Dies macht die Sache schon deutlich komplexer. Andererseits müssen die Knoten ihre Daten untereinander synchronisieren, was durch Abhören der Netzwerkkommunikation einen erstmals durchaus vielversprechenden Angriffsvektor definiert.

Hat der Angreifer Zugriff auf einen oder mehrere Blöcke, so können die darin enthaltenen Informationen ausgelesen werden. Um ein Bloßlegen sensibler Daten zu verhindern, müssen damit die im Block enthaltenen Daten zusätzlich verschlüsselt werden. Das ist in dieser einfachen Implementierung nicht gegeben, in der Praxis aber ein eher einfach zu lösendes Problem.

Erweitern wir nun den Zugriff des Angreifers: Dieser hätte einen Server-Knoten komplett unter seine Gewalt bekommen. Und wir gehen noch weiter: Die Informationen der Blöcke sind im Klartext bekannt. Diese Situation wäre in einer klassischen Architektur vergleichbar mit einem korrumpierten Datenbank-Administrator, der den Datenbank-Host kontrolliert. Dass damit bereits beträchtlicher Schaden angerichtet ist, ist vollkommen klar. Aber fast noch schlimmer wäre es nun, die Daten manipulieren zu können. So könnte beispielsweise versucht werden, eine wichtige Information nachträglich zu ändern. Was muss der Angreifer alles machen:

  1. Der Block muss die geänderte Information gesetzt bekommen.
  2. Er muss einen neuen Hash erzeugen und auf diese Art und Weise einen komplett neuen, konsistenten Block erzeugen. Dies ist bereits die erste Komplikation.
  3. Nun muss der manipulierte Block in die Blockchain integriert werden. Und nun wird es wirklich kompliziert: Denn nicht nur der eine manipulierte Block muss geändert werden, sondern auch alle (!) Nachfolger. Denn diese beziehen sich auf einen Parent-Block, der so ja gar nicht mehr in der Chain enthalten ist. Der Aufwand für den Angreifer und damit die Wahrscheinlichkeit, dass die Manipulation entdeckt wird steigt bereits hier drastisch.
  4. Und zum Schluss muss der Angreifer die anderen Knoten des verteilten Systems „überzeugen“, diese Änderungen komplett zu übernehmen.

Schon der dritte Punkt ist so aufwändig zu realisieren, dass die Wahrscheinlichkeit eines Erfolgs des Angriffs drastisch sinkt. Punkt 4 übersteigt endgültig die Fähigkeiten eines realistischen Angreifers.

Der folgende Test simuliert einen Angreifer, der die Java-Anwendung angreift. Der Versuch ist erfolgreich bis zu Punkt zwei, aber mehr auch nicht:

Ausblick

Um ein funktionierendes, auf Blockchain-Technologie basierendes System in Betrieb nehmen zu können fehlen noch

  • Das verteilte System mit den kommunizierenden Knoten
  • Authentifizierung, Autorisierung und Verschlüsselung
  • Eine Implementierung einer fachlich konsistenten Validierung der Block-Daten
  • Und schließlich noch eine Logik für fachliche Abfragen.

 

 

Bild von analogicus auf Pixabay

 

 

Weiterlesen

Swift und Java

Java und Apple Swift

Apple Swift – Eine moderne Programmiersprache

Mit der Programmiersprache Swift hat Apple ein modernes Werkzeug für die Anwendungsentwicklung für Mac und iOS bereit gestellt. Diese Sprache löst das von vielen Entwicklern als etwas gewöhnungsbedürftig und sperrig betrachtete Objective C ab.  Mit der aktuellen Version 3 steht eine erste vollständige und unabhängige Implementierung zur Verfügung. Die anstehende Version 4 wird weitere Features einführen, jedoch keine Änderungen an der Core-Sprache mehr vornehmen.

Swift wurde von Apple als Open Source-Initiative freigegeben und steht damit auch für andere Plattformen zur Verfügung, z.B. für Ubuntu. Eine durchaus beachtenswerte Abkehr von der bisherigen Abschottung der Apple-Produkte. Allerdings gilt dies natürlich nur für den Kern der Sprache, die App-Programmierung muss aus Lizenz-Gründen weiterhin unter Apple Hardware und Betriebssystem erfolgen. Diese Einschränkung ist für diesen Artikel allerdings nicht relevant, da ich mich hier bewusst auf den Vergleich der Programmiersprachen konzentrieren möchte; für einen (durchaus interessanten!) Vergleich von Google Android  und Apple Swift gibt es andere Artikel.

Swift vereinigt etablierte Konzepte aus Sprachen wie Java, C#, JavaScript und natürlich auch Objective C und ergänzt diese durch eigene Ideen. Damit finden Programmierer einesteils recht viel Bekanntes, aber eben auch unerwartete und damit überraschende Konstrukte.  Hier möchte ich auf die Unterschiede zu Java eingehen, die aus meiner Erfahrung heraus relevant sind.

Swift und Java – Welche Konzepte sind interessant?

Für Java-Entwickler ist Swift auch deshalb interessant, weil einige Konzepte durchaus auch in einer zukünftigen Java-Version Einzug halten könnten. Weiterhin gibt es doch eine Reihe von Besonderheiten, die den Einstieg in Swift erschweren könnten.

Konsequente Type Inference

Swift ist wie Java streng und statisch typisiert. Damit prüft der Swift-Compiler, dass einer einmal deklarierten Variable kein Wert eines anderen Datentyps zugewiesen werden kann.

Allerdings ist eine Typ-Angabe bei der Deklaration optional; der Typ kann meistens aus dem Typen der Zuweisung bestimmt werden:

 

Optionals

Sehr gut gelöst ist meiner Meinung nach der Umgang mit Null-Werten, in Swift nilgenannt. Einer Variablen muss ein Nicht-Null-Wert zugewiesen werden, es sei denn, sie wird explizit als Optional-Typ deklariert:

Optionals sind in Swift eigene Typen, so dass der Compiler bei Zuweisungen die normale Typ-Prüfung durchführt und Fehler erkennt:

Optionale Typen müssen vor ihrer weiteren Verwendung „ausgepackt“=unwrapped werden. Dafür gibt es in Swift zwei Möglichkeiten:

  • Explizites Unwrap mit dem !-Operator
  • Sicheres Unwrap über die if -let -Konstruktion:

Obwohl diese Sequenzen für einen Java-Entwickler erst einmal merkwürdig aussehen liegt der Vorteil auf der Hand: Bereits der Compiler erkennt  Zuweisungen von Null-Werten, so dass der Entwickler auf null-Prüfungen oder das Fangen einer NullPointerException verzichten kann.

Und dann haben wir noch das „Optional Chaining“ beim Zugriff auf Eigenschaften eines Objekts:

Falls message2 nil sein sollte wird die hasPrefix-Methode nicht ausgeführt.

Klassen und Strukturen in Swift

Swift kennt zwei unterschiedliche Definitionen eines benutzerdefinierten Datentyps: Klassen und Strukturen.

Während Instanzen von Klassen wie in Java stets über Referenzen angesprochen werden, werden Strukturen immer als Werte angesehen:

Swift - Der Unterschied zwischen Strukturen und Klassen
Der Unterschied zwischen Strukturen und Klassen

Ganz besonders verwirrend für Java-Entwickler ist, dass alle Collections-Implementierungen in Swift als Strukturen realisiert wurden!

Weitere Besonderheiten sind eher unter „syntactic sugar“ zu sehen:

  • Einfache Definition von Properties durch get– und set-Blöcke
  • Bei Strukturen werden die Konstruktoren automatisch angelegt

Extensions

Alle Klassen und Strukturen sind in Swift „Open for Extension“. Das bedeutet, dass auch ohne Vererbung vorhandene Klassen jederzeit erweitert werden können. Nur zur Klarstellung: Dies gilt selbstverständlich auch für die Klassen der Standard-Bibliothek!

Zur Definition wird das Schlüsselwort extension benutzt. Im Folgenden eine (zugegebenermaßen triviale) Erweiterung der Person-Klasse sowie ein neuer Konstruktor für String:

 

Extensions können eine Klasse nicht mit neuen Attributen ausstatten. get– und set-Blöcke können jedoch verwendet werden.

Verschiedenes

  • Neben Klassen und Strukturen unterstützt Swift auch Enums und Tuples
  • Als Zeichen für Namen von Variablen oder Funktionen können beliebige Unicode-Zeichen benutzt werden.
  • Funktionsparameter haben eine  internen und gegebenenfalls einen öffentlichen Namen, der beim Aufruf mitgegeben werden muss:

    Sollen die Parameter nicht benannt sein wird der Unterstrich als öffentlicher Name benutzt:
  • Die Swift-Installation enthält eine REPL, so dass Sequenzen und einfache Anwendungen auch ohne Installation einer Entwicklungsumgebung ausgeführt werden können.
  • Schnittstellen heißen in Swift protocol, nicht interface.
  • Mit der String Interpolation werden Variablen bzw. Ausdrücke direkt in Zeichenketten ausgewertet:

  • Operatoren können jederzeit geändert oder für eigene Datentypen definiert werden

  • Auch neue Operatoren sind einfach zu deklarieren. So wird im folgenden Beispiel das Unicode-Zeichen für das Herz-Symbol als Operator zwischen zwei Personen definiert:

 

Die Beispiele

Die im Artikel beschriebenen Code-Fragmente stehen über meinen GitHub-Account zur freien Verfügung und können gerne für eigene Experimente benutzt werden. Die Sourcen gibt es hier.

Die Beispiele benötigen eine Swift-Installation, ich habe hierzu die Ubuntu-Installation benutzt.


Seminar zum Thema

Weiterlesen

Project Lombok - Java scharf gewürzt

Project Lombok – Java Klassen scharf gewürzt

 Die Motivation hinter Project Lombok

Was steckt eigentlich hinter dem „Project Lombok“? Jeder Java-Entwickler kennt das Problem bei der Erstellung einer einfachen Datenstruktur. Die eigentliche Modellierung und Definition der Attribute einer Klasse ist erst einmal einfach:

Anschließend müssen dann aber erst einmal aufwändig weitere notwendige Elemente geschrieben werden:

  • Getter- und Setter-Methoden
  • Konstruktoren
  • hashCode und equals
  • toString

 

Ohne die Hilfe einer Entwicklungsumgebung wie Eclipse, IntelliJ oder ähnliches wäre dieser Aufwand absurd hoch!

Ausschnitt des Kontext-Menüs zur Code-Generierung in Eclipse
Ausschnitt des Kontext-Menüs zur Code-Generierung in Eclipse

Die Intention des Lombok-Projekts  ist es, diesen Aufwand zu vermeiden. Insbesondere bei Änderungen der Datenstruktur müssten ja sonst alle diese Aktionen nochmals neu ausgeführt werden, damit Inkonsistenzen vermieden werden. Mit Lombok muss der Entwickler nur noch Annotationen definieren, die bei jedem Compiler-Lauf neu ausgewertet werden und folglich den aktuellen Stand repräsentieren.

Ein Beispiel mit Project Lombok

Betrachten wir doch einmal das Outline der oben dargestellten Klasse Person und vergleichen diese mit dem der Klasse LombokPerson

Ein Vergleich der Struktur zweier Klassen zeigt keine Unterschiede
Ein Vergleich der Struktur zweier Klassen

Selbst bei genauer Betrachtung lässt sich hier, außer dem Namen der Klasse, kein Unterschied erkennen. Nun aber der Quellcode der Klasse LombokPerson:

Das ist tatsächlich alles! Keine Konstruktoren, keine Setter etc. Das alles wurde automatisch an Hand der Annotationen erzeugt.

Details zur Arbeitsweise

  • Lombok stellt einen Annotation Processor zur Verfügung, der die notwendigen Code-Elemente automatisch erstellt. Dafür ist es nur notwendig, die lombok.jar dem Projekt hinzuzufügen und über die IDE das Annotation Processing zu aktivieren. Dann wird der Code generiert und anschließend compiliert.
  • Falls der Entwickler tatsächlich den generierten Java-Code benutzen möchte, kann hierfür delombok benutzt werden.
  • Die Code-Generierung kann durch die Angabe weitere Annotationen entsprechend fein angepasst werden. Damit können beispielsweise die in hashCode und equals auszuwertenden Attribute definiert oder der parameterlose Konstruktor generiert werden.
  • Zur Integration in Entwicklungsumgebungen steht in der lombok.jar eine ausführbare Installationsroutine zur Verfügung.

 

Der Installer für Project Lombok
Der Lombok-Installer, hier für eine Eclipse-Installation
  • Selbstverständlich kann Lombok auch in automatisierte Buildprozesse integriert werden. Für einen Maven-getriebenen Prozess genügt es beispielsweise, die Abhängigkeit auf Lombok in der POM einzutragen:

     

Bewertung

Mit Lombok steht meiner Meinung nach ein wirklich sinnvolles Werkzeug zur Verfügung, das den Aufwand bei der Erstellung von Java-Datenklassen deutlich verringert. Programmierern, die sich auch im C#-, Swift oder Groovy-Umfeld bewegen, wird diese Art der Entwicklung sehr bekannt vorkommen. Java ist in diesem Bereich selbst in der Version 8 immer noch ziemlich altbacken, überdies ist eine echte Verbesserung leider auch in der Java 9 -Roadmap nicht erkennbar. Lombok wird deshalb auch noch mittelfristig sinnvoll eingesetzt werden.

Mit den „Experimental Features“ werden weitere hochinteressante Elemente eingeführt, die allerdings teilweise einen Überlapp zur Aspekt-orientierten Programmierung aufweisen. Ob diese Annotationen in eigenen Projekten sinnvoll benutzt werden können muss individuell entschieden werden. Nicht vergessen: Project Lombok ist Open Source und folglich Community-getrieben! Welche Richtung dieses Projekt in Zukunft nehmen wird kann deshalb jeder aktiv mit beeinflussen.

Bildnachweis: pixabay ch1310 CC0 Public Domain


Seminar zum Thema

Weiterlesen

DockerDuke

Docker und Java – Teil 3: Der Build-Prozess

Im zweiten Teil der Reihe wurden die notwendigen Werkzeuge vorgestellt und installiert. Nun werden wir den Build-Prozess für Java-Projekte und die Erstellung der Docker-Images zusammenführen.

Teil 3: Der Build-Prozess

Build von Java-Projekten mit Apache Maven

Apache Maven ist neben Apache Ant mit Ivy und Gradle ein Standard-Werkzeug, das zum automatisierten Erzeugen von Java-Archiven benutzt werden kann. Allen Werkzeugen gemeinsam ist das Dependency Management: Projekt-Abhängigkeiten werden in einer Konfigurationsdatei abgelegt und vom Build-Werkzeug automatisch aus einem Artefakt-Repository geladen. Repositories werden von verschiedenen Anbietern frei zugänglich im Internet betrieben. Maven Central ist das wahrscheinlich bekannteste Beispiel.

Um die selbst erzeugten Artefakte selbst verwalten zu können, werden im Unternehmen meistens eigene Server betrieben. Dazu existieren sofort einsetzbare Produkte wie Sonatype NexusJFrog Artefactory oder Apache Archiva.

Entscheiden wir uns für einen Maven-basierten Build-Prozess erfolgt die allgemeine Konfiguration des Build-Prozesses mit zwei Dateien:

  • Die settings.xml enthält die URL des Artefakt-Repositories und gegebenenfalls Authentifizierungs-Informationen

 

Ein Parent-POM enthält neben allgemeinen Informationen für alle Build-Prozesse auch die Informationen zum Ausbringen der Artefakte in das Repository

 

Nach all diesen Vorbereitungen ist der Build-Prozess eines eigenen Projekts sehr einfach: Es wird ein Projekt-POM definiert, das im einfachsten Fall nur den Parent angeben muss.

 

Trotz dieser wirklich sehr einfachen Konfiguration kann das Java-Projekt sofort bis hin zu verschiedenen Phasen gebaut werden:

  • compile: Das Projekt wird kompiliert
  • package: Ein Java-Archiv wird im target-Verzeichnis des Projekts erzeugt
  • deploy: Das Archiv wird in das Unternehmens-Repository ausgebracht

So einfach funktioniert Maven!

Ein Maven System
Ein Maven System

Maven und Docker

Auch Docker definiert einen Build-Prozess: Images werden aus dem Dockerfile erzeugt. Was liegt also näher, als diesen Prozess mit Maven zu integrieren? Diese Idee wird durch Maven-PlugIns für Docker umgesetzt. Hierzu stehen sogar verschieden Produkte zur Auswahl:

 

  • Durch das Parent-POM ist die Integration dieser PlugIns für den Entwickler vollkommen transparent! Wird beispielsweise das Spotify-PlugIn in den Parent aufgenommen

 

 

so stehen nun neue Maven-Befehle zur Verfügung, insbesondere

  • docker:build: Erzeugen des Images aus dem Dockerfile des Projekts
  • docker:push: Pushen des Images in ein Docker-Repository

Damit ist die gewünschte Integration der Build-Prozesse durchgeführt. Und nachdem Nexus oder Artefactory neben Java-Artefakten auch Docker-Images verwalten können, ist unser System praktisch fertig! Dass die Quellcodes, das POM und das Dockerfile in einem Versionsverwaltungssystem abgelegt werden und auf ein Build-Server wie Jenkins die Builds automatisiert ablaufen lassen wird, ist selbstverständlich.

Die vollständige Parent-POM kann hier angezeigt werden:

 


Im vierten und letzten Teil wird dann programmiert: Wir erstellen einen Microservice auf Basis von Spring Boot!


Seminare zum Thema

 

Weiterlesen

DockerDuke

Docker und Java Teil 2 – Installation und erstes Arbeiten

Nachdem wir uns im ersten Teil der Reihe um Docker gekümmert haben geht es im zweiten Teil um die Installation der Werkzeuge, die für ein effizientes Arbeiten mit Docker und Java notwendig sind.

Teil 2: Installation und erstes Arbeiten

SUSE Linux Enterprise

Schritte

Die Installation von Docker auf verschiedenen Plattformen ist in der Dokumentation sehr gut beschrieben. Dabei ist auf Linux-Systemen wie SUSE Enterprise diese Routine sehr einfach durchzuführen:

  1. Hinzufügen des Docker-Repositories mit sudo zypper addrepo https://yum.dockerproject.org/repo/main/opensuse/13.2/ docker-main
  2. Refresh des SUSE Package Managers mit sudo zypper refresh
  3. Die eigentliche Installation erfolgt mit sudo zypper install docker-engine

Während der Installation werden eventuell einige Warnungen bezüglich Signaturen etc. angezeigt, die aber einfach akzeptiert werden können.

Docker ist hiermit installiert, wie einfach überprüft werden kann:

docker -v
mit der Ausgabe
Docker version 1.13.1, build 092cba3

Andererseits scheitern alle anderen docker-Befehle an fehlenden Berechtigungen. Dies liegt aber nur daran, dass der Docker-Dämon als root-Benutzer ausgeführt wird. Zur Lösung gibt es zwei Möglichkeiten:

  • Arbeiten mit sudo. Dies ist ziemlich „quick & dirty“ und auf Dauer nicht genügend.
  • Hinzufügen von Usern zur Gruppe docker. Dies ist die saubere Lösung, die jetzt beschrieben wird:
    1. Erstellen der Gruppe docker mit sudo groupadd docker. Allerdings ist diese  Gruppe wahrscheinlich bereits bei der Installation angelegt worden.
    2. Anschließend wird der User  mit sudo gpasswd -a ${USERNAME} docker hinzugefügt.

Nach einer Neuanmeldung am System ist die Installation komplett. Der Start des Dämons erfolgt mit: sudo service docker start.

Was ist während der Installation alles passiert?

  • Es wurde der Docker-Dämon installiert und gestartet. Dieser verwaltet alle Images und Container. Außerdem ist er in der Lage, über https mit dem Docker-Hub-Repository zu kommunizieren.
  • Es wurde ein lokales Repository für Images und Container angelegt. Dieses befindet sich in /var/lib/docker
  • Der Docker-Client ist ein Konsolen-Programm, mit dessen Hilfe an den Docker-Dämon Befehle gesendet werden können. Dieser Client ist für einen Benutzer das primäre Werkzeug.
Docker Werkzeuge
Die Bestandteile von Docker im Zusammenspiel

Kurzübersicht wichtiger Docker-Kommandos

Der Befehlssatz des Docker-Clients ist umfangreich, eine detaillierte Beschreibung ist in der Referenz-Dokumentation aufgeführt. Wichtige Befehle sind:

  • pull: Lädt ein Image vom entfernten Repository
  • create: Erzeugt einen Container
  • start|stop: Start/Stop eines Containers
  • run: Erzeugt einen Container und startet diesen sofort
  • build: Erstellt ein Image

Eclipse und das Docker-PlugIn

Eclipse wird für SUSE Linux  als Archiv zur Verfügung gestellt. Nach dem Download wird dieses anschließend extrahiert. Dann wird das Docker-PlugIn installiert. Damit stehen schließlich innerhalb der Java-Entwicklungsumgebung Views zur Benutzung von Docker-Befehlen zur Verfügung. Oder anders formuliert: Ein Java-Entwickler benutzt das PlugIn mit Dialogen und Kontextmenüs statt des Konsolen-basierten Docker-Clients. Weiterhin existiert ein eigener Editor, der das Format eines Dockerfiles unterstützt. Und schließlich werden in einer Übersicht alle vorhandenen Images und Container angezeigt.

Nach dem Öffnen der Docker Tooling Perspektive findet das PlugIn automatisch eine Verbindung zum Docker-Dämon auf dem lokalen Rechner. Sollte dies nicht der Fall sein, so ist wahrscheinlich der aktuelle Benutzer nicht Bestandteil der docker-Gruppe und hat folglich keine Zugriffs-Berechtigung. In diesem Fall prüfen Sie bitte Ihre Installation und melden sich anschließend nochmals neu an.

Erstes Arbeiten

Jetzt ist die Bühne bereitet, um ein erstes eigenes Java-Image zu erstellen und auszuführen!

Dazu erzeugen wir im Dockerfile-Editor die folgende Textdatei namens Dockerfile:

FROM openjdk:latest
ENTRYPOINT java -version

Ein Rechtsklick auf das Dockerfile öffnet das Kontextmenü:

Run As - Docker Image Build

Die Ausgaben zeigen zwei Schritte:

  1. Erstens wird das  openjdk-Layer geladen. Dies kann etwas dauern, da es einmalig von Docker-Hub geladen werden muss.
  2. Zweitens wird der EntryPoint hinzugefügt. Dies erzeugt faktisch ein weiteres Layer.

Entry Point

Genauso hätte das Erzeugen des Images auch über den Befehl
docker build -t javacream
erfolgen können.

Was haben wir nun alles im lokalen Repository? Das zeigt die Explorer-View:

 Explorer-View lokalen Repository

Neben unserem eben erzeugten Image wurde somit automatisch das in der FROM-Klausel angegebenen Basis-Image geladen.

Zum Abschluss erzeugen wir noch einen temporären Container, der das Image als Vorlage hat und anschließend gestartet wird. Dies erreichen wir, indem im Kontextmenü des Images Run... aufgerufen wird:

Temporärer Container mit Image als Vorlage

Mit der Ausgabe:

Log for Container

Auch hier hätte ein Kommando den gleichen Effekt gehabt, beispielsweise

docker run --rm javacream


Im nächsten Teil des Artikels geht es um das Build-Management. Wie kann das Erzeugen der Docker-Images automatisiert werden? Und wie werden Images über ein Repository zur Verfügung gestellt?


Seminare zum Thema

Konferenzen zum Thema

  • DevOpsCon
  • Die Konferenz für Continuous Delivery, Microservices, Docker, Clouds & Lean Business

Weiterlesen