Containerisierung von Java-Anwendungen mit Docker: Schritt-für-Schritt-Anleitung

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Docker, Java und warum dies die Spielregeln ändert

\n\n

Stellen Sie sich vor: Sie haben eine coole Java-Anwendung geschrieben. Sie funktioniert auf Ihrem MacBook, aber wenn Sie sie einem Kollegen unter Windows geben – alles geht kaputt. Kommt Ihnen bekannt vor? Und wenn der Server unter Linux läuft? Da muss man nicht einmal raten – die klassische Geschichte "bei mir funktioniert es".

\n\n

Die Containerisierung mit Docker löst dieses Problem ein für alle Mal. Sie verpacken die Anwendung zusammen mit ihrer Umgebung (JVM, Bibliotheken, Abhängigkeiten) in einen leichten Container, der überall gleich läuft. Für Java ist das besonders relevant – denn wir sind zwar an "Write Once, Run Anywhere" gewöhnt, aber in der Praxis versagt diese Redewendung oft aufgrund von JDK-Versionen, Systembibliotheken oder Konfigurationen.

\n\n

In diesem Artikel behandeln wir die Containerisierung von Java-Anwendungen mit Docker von A bis Z. Sie erfahren, wie Sie ein Dockerfile schreiben, das Image optimieren, Docker Compose verwenden und nicht in typische Fallen tappen. Los geht's!

\n\n

Was ist Docker und warum braucht ein Java-Entwickler es?

\n\n

Docker ist eine Plattform zum Verpacken, Ausliefern und Ausführen von Anwendungen in isolierten Umgebungen – den Containern. Im Gegensatz zu virtuellen Maschinen nutzen Container den gemeinsamen OS-Kernel, haben aber ihren eigenen Dateibereich, ihr Netzwerk und ihre Prozesse. Das macht sie leicht (Megabyte statt Gigabyte) und schnell (Start in Sekunden).

\n\n

Für einen Java-Entwickler bietet Docker drei Superkräfte:

\n
    \n
  • Reproduzierbarkeit – kein "bei mir funktioniert es" mehr. Wenn der Container lokal läuft, läuft er auf jedem Server.
  • \n
  • Isolation – jede Anwendung lebt in ihrer eigenen Welt, ohne andere zu stören. Sie möchten zwei Java-Anwendungen mit verschiedenen JDK-Versionen? Kein Problem.
  • \n
  • Skalierung – Container lassen sich leicht klonen, ausbalancieren und orchestrieren (Kubernetes, Docker Swarm).
  • \n
\n\n

Das erste Dockerfile für eine Java-Anwendung

\n\n

Fangen wir einfach an. Wir haben eine Standard-Java-Anwendung (z. B. Spring Boot oder einfach Main.java). Wir möchten sie in ein Docker-Image verpacken. Der einfachste Weg ist die Verwendung des offiziellen OpenJDK-Images.

\n\n

Hier ist ein minimales Dockerfile:

\n\n
# Verwenden des offiziellen OpenJDK 17 Images\nFROM openjdk:17-jdk-alpine\n\n# Arbeitsverzeichnis festlegen\nWORKDIR /app\n\n# JAR-Datei in den Container kopieren\nCOPY target/my-app.jar /app/my-app.jar\n\n# Anwendung starten\nCMD ["java", "-jar", "my-app.jar"]
\n\n

Jetzt bauen wir das Image und starten den Container:

\n\n
# Image bauen\ndocker build -t my-java-app .\n\n# Container starten\ndocker run -p 8080:8080 my-java-app
\n\n

Alles funktioniert. Aber das ist ein schlechtes Beispiel. Warum? Schauen wir uns das an.

\n\n

Problem Nr. 1: Image-Größe

\n

Das Image openjdk:17-jdk-alpine wiegt etwa 150 MB. Das ist in Ordnung, aber wenn Sie alle Abhängigkeiten hinzufügen, kann die Größe auf über 500 MB anwachsen. Für die Produktion ist das viel.

\n\n

Problem Nr. 2: Build und Runtime in einem Image

\n

Wir kopieren ein fertiges JAR, das bedeutet, der Build (mvn clean package) muss vorher erfolgen. Besser ist die Verwendung eines Multi-Stage-Builds, um die Kompilierungsphase von der Ausführungsphase zu trennen.

\n\n

Optimierung: Multi-Stage-Build

\n\n

Die Idee ist einfach: In der ersten Phase verwenden wir ein Image mit Maven und JDK, bauen das Projekt, und in der zweiten Phase nur JRE und das fertige JAR. Das reduziert das endgültige Image um ein Vielfaches.

\n\n
# Build-Phase\nFROM maven:3.8.5-openjdk-17 AS builder\nWORKDIR /build\nCOPY pom.xml .\nCOPY src ./src\nRUN mvn clean package -DskipTests\n\n# Ausführungsphase\nFROM openjdk:17-jre-alpine\nWORKDIR /app\nCOPY --from=builder /build/target/my-app.jar /app/my-app.jar\nEXPOSE 8080\nCMD ["java", "-jar", "my-app.jar"]
\n\n

Was hat sich geändert?

\n
    \n
  • Die erste Phase (builder) enthält Maven und JDK – sie wird nur für die Kompilierung benötigt.
  • \n
  • Die zweite Phase verwendet ein leichtes JRE-Image (~50 MB).
  • \n

Blogs

Buchempfehlungen