Einführung in Docker und Java
Moderne Java-Entwicklung ist ohne Containerisierung undenkbar. Docker ist eine Plattform zum Verpacken, Bereitstellen und Ausführen von Anwendungen in isolierten Umgebungen (Containern). Für Java-Entwickler löst Docker das ewige Problem: „Auf meinem Rechner funktioniert es!“. Der Container garantiert, dass Ihre Anwendung auf dem lokalen Rechner, dem Entwicklungsserver und in der Produktion identisch läuft.
In diesem Artikel werden wir uns ansehen, wie man Java-Anwendungen mit Docker containerisiert: von einem einfachen Dockerfile bis zur Optimierung von Images für eine Microservices-Architektur. Alle Beispiele sind in Java geschrieben und einsatzbereit.
Grundlagen von Docker für Java-Anwendungen
Was ist ein Docker-Image und ein Container?
Ein Docker-Image ist eine schreibgeschützte Vorlage, die alles enthält, was zum Ausführen einer Anwendung benötigt wird: JVM, Bibliotheken, Code und Konfigurationen. Ein Container ist eine laufende Instanz eines Images. Für Java bedeutet dies, dass Sie das JDK nicht manuell auf dem Server installieren müssen – die JVM befindet sich bereits im Container.
Erstellen eines einfachen Dockerfile für Java
Betrachten wir ein einfaches Beispiel. Wir haben eine einfache Java-Anwendung (z. B. HelloWorld.java).
// HelloWorld.javapublic class HelloWorld { public static void main(String[] args) { System.out.println("Hello from Docker and Java!"); }}Erstellen wir ein Dockerfile:
# Verwende das offizielle OpenJDK-ImageFROM openjdk:11-jre-slim
# Lege das Arbeitsverzeichnis festWORKDIR /app
# Kopiere die kompilierte jar- oder class-DateienCOPY HelloWorld.class .
# StartbefehlCMD ["java", "HelloWorld"]Build und Start:
# Image bauendocker build -t hello-java .
# Container startendocker run hello-javaAusgabe: Hello from Docker and Java!
Containerisierung von Spring Boot-Anwendungen
Für reale Projekte (z. B. mit Spring Boot) wird der Prozess komplexer. Betrachten wir einen typischen Microservice.
Multi-Stage-Build
Dies ist die beste Praxis für Java: Zuerst wird die Anwendung mit dem vollständigen JDK gebaut, dann wird das Ergebnis in ein leichtgewichtiges JRE-Image kopiert.
# Stufe 1: BuildFROM maven:3.8.5-openjdk-11 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn clean package -DskipTests
# Stufe 2: AusführungFROM openjdk:11-jre-slimWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]Erklärung:
- build – verwendet Maven und das vollständige JDK zur Kompilierung.
- Finales Image – enthält nur die JRE und die fertige jar-Datei. Die Image-Größe reduziert sich um das 2- bis 3-fache.
Optimierung des Layer-Cachings
Docker cached jeden Layer (Anweisung). Um den Build zu beschleunigen, platzieren Sie selten geänderte Abhängigkeiten am Anfang:
FROM maven:3.8.5-openjdk-11 AS buildWORKDIR /app# Abhängigkeiten cachenCOPY pom.xml .RUN mvn dependency:go-offline# Jetzt den Code kopierenCOPY src ./srcRUN mvn clean packageWenn Sie jetzt nur den Code ändern, baut Docker nur die letzten Layer neu, während die Abhängigkeiten aus dem Cache kommen.
Arbeiten mit Umgebungsvariablen und Profilen
Parameter an die Java-Anwendung übergeben
Docker ermöglicht die flexible Konfiguration der Anwendung über Umgebungsvariablen. Für Spring Boot ist das besonders praktisch.
docker run -e SPRING_PROFILES_ACTIVE=prod -e DB_URL=jdbc:postgresql://db:5432/mydb my-appIm Dockerfile können Standardwerte festgelegt werden:
ENV SPRING_PROFILES_ACTIVE=devENV DB_URL=jdbc:h2:mem:testdbBeispiel docker-compose für Java + DB
Für Microservices ist die Verwendung von docker-compose.yml praktisch:
version: '3.8'services: app: bu