Hier ist mein Beitrag.
Ich werde nicht versuchen, alle Tools / Bibliotheken / Plugins aufzulisten, die vorhanden sind, um Docker mit Maven zu nutzen. Einige Antworten haben es bereits getan.
Stattdessen werde ich mich auf die Anwendungstypologie und den Dockerfile-Weg konzentrieren.
Dockerfile
ist wirklich ein einfaches und wichtiges Konzept von Docker (alle bekannten / öffentlichen Bilder hängen davon ab) und ich denke, dass der Versuch, das Verstehen und Verwenden von Dockerfile
s zu vermeiden, nicht unbedingt der bessere Weg ist, in die Docker-Welt einzutreten.
Das Andocken einer Anwendung hängt von der Anwendung selbst und dem zu erreichenden Ziel ab
1) Für Anwendungen, die wir auf einem installierten / eigenständigen Java-Server ausführen möchten (Tomcat, JBoss usw.)
Der Weg ist schwieriger und das ist nicht das ideale Ziel, da dies die Komplexität erhöht (wir müssen den Server verwalten / warten) und weniger skalierbar und weniger schnell als eingebettete Server in Bezug auf das Erstellen / Bereitstellen / Aufheben der Bereitstellung ist.
Bei älteren Anwendungen kann dies jedoch als erster Schritt betrachtet werden.
Im Allgemeinen besteht die Idee hier darin, ein Docker-Image für den Server zu definieren und ein Image pro zu implementierender Anwendung zu definieren.
Die Docker-Images für die Anwendungen erzeugen das erwartete WAR / EAR, diese werden jedoch nicht als Container ausgeführt, und das Image für die Serveranwendung stellt die von diesen Images erzeugten Komponenten als bereitgestellte Anwendungen bereit.
Für große Anwendungen (Millionen von Codezeilen) mit vielen Legacy-Inhalten und so schwer zu migrieren, um auf eine eingebettete Full-Spring-Boot-Lösung zu migrieren, ist das wirklich eine schöne Verbesserung.
Ich werde diesen Ansatz nicht näher erläutern, da dies für kleinere Anwendungsfälle von Docker gilt, aber ich wollte die Gesamtidee dieses Ansatzes erläutern, da ich denke, dass es für Entwickler, die sich diesen komplexen Fällen stellen, gut ist zu wissen, dass einige Türen geöffnet sind Docker integrieren.
2) Für Anwendungen, die den Server selbst einbetten / booten (Spring Boot mit eingebettetem Server: Tomcat, Netty, Jetty ...)
Das ist das ideale Ziel mit Docker . Ich habe Spring Boot spezifiziert, weil dies ein wirklich schönes Framework ist, das auch ein sehr hohes Maß an Wartbarkeit aufweist, aber theoretisch könnten wir jeden anderen Java-Weg verwenden, um dies zu erreichen.
Im Allgemeinen besteht die Idee hier darin, ein Docker-Image pro bereitzustellender Anwendung zu definieren.
Die Docker-Images für die Anwendungen erzeugen eine JAR oder eine Reihe von JAR- / Klassen- / Konfigurationsdateien. Diese starten eine JVM mit der Anwendung (Java-Befehl), wenn wir aus diesen Images einen Container erstellen und starten.
Für neue Anwendungen oder Anwendungen, die für die Migration nicht zu komplex sind, muss dieser Weg gegenüber eigenständigen Servern bevorzugt werden, da dies der Standardweg und der effizienteste Weg zur Verwendung von Containern ist.
Ich werde diesen Ansatz detailliert beschreiben.
Andocken einer Maven-Anwendung
1) Ohne Spring Boot
Die Idee ist, mit Maven ein Fat Jar zu erstellen (das Maven Assembly Plugin und das Maven Shade Plugin helfen dabei), das sowohl die kompilierten Klassen der Anwendung als auch die erforderlichen Maven-Abhängigkeiten enthält.
Dann können wir zwei Fälle identifizieren:
Wenn es sich bei der Anwendung um eine Desktop- oder autonome Anwendung handelt (die nicht auf einem Server bereitgestellt werden muss): Wir können wie CMD/ENTRYPOINT
in Dockerfile
der Java-Ausführung der Anwendung Folgendes angeben :java -cp .:/fooPath/* -jar myJar
Wenn es sich bei der Anwendung um eine Serveranwendung handelt, z. B. Tomcat, ist die Idee dieselbe: ein dickes Glas der Anwendung abzurufen und eine JVM in der Anwendung auszuführen CMD/ENTRYPOINT
. Aber hier mit einem wichtigen Unterschied: Wir müssen einige logische und spezifische Bibliotheken ( org.apache.tomcat.embed
Bibliotheken und einige andere) einbeziehen, die den eingebetteten Server starten, wenn die Hauptanwendung gestartet wird.
Wir haben einen umfassenden Leitfaden auf der Heroku-Website .
Für den ersten Fall (autonome Anwendung) ist dies eine einfache und effiziente Möglichkeit, Docker zu verwenden.
Für den zweiten Fall (Serveranwendung) funktioniert dies, ist aber nicht eindeutig, kann fehleranfällig sein und ist kein sehr erweiterbares Modell, da Sie Ihre Anwendung nicht in den Rahmen eines ausgereiften Frameworks wie Spring Boot stellen, das viele Funktionen ausführt von diesen Dingen für Sie und bietet auch ein hohes Maß an Erweiterung.
Dies hat jedoch einen Vorteil: Sie haben ein hohes Maß an Freiheit, da Sie die eingebettete Tomcat-API direkt verwenden.
2) Mit Spring Boot
Endlich geht es los.
Das ist einfach, effizient und sehr gut dokumentiert.
Es gibt wirklich mehrere Ansätze, um eine Maven / Spring Boot-Anwendung auf Docker auszuführen.
Alle aufzudecken wäre lang und vielleicht langweilig.
Die beste Wahl hängt von Ihren Anforderungen ab.
Wie auch immer, die Build-Strategie in Bezug auf Docker-Ebenen sieht gleich aus.
Wir möchten einen mehrstufigen Build verwenden: einen, der sich für die Abhängigkeitsauflösung auf Maven und für den Build stützt, und einen anderen, der sich beim Starten der Anwendung auf JDK oder JRE stützt.
Bauphase (Maven-Bild):
- pom Kopie zum Bild
- Downloads von Abhängigkeiten und Plugins.
Über das, mvn dependency:resolve-plugins
angekettet an mvn dependency:resolve
den Job kann zu tun , aber nicht immer.
Warum ? Da diese Plugins und die package
Ausführung zum Packen des Fat Jars möglicherweise von unterschiedlichen Artefakten / Plugins und sogar von demselben Artefakt / Plugin abhängen, wird möglicherweise immer noch eine andere Version verwendet. Ein sicherer Ansatz, der möglicherweise langsamer ist, besteht darin, Abhängigkeiten aufzulösen, indem genau der mvn
Befehl ausgeführt wird, der zum Packen der Anwendung verwendet wird (wodurch genau die benötigten Abhängigkeiten abgerufen werden), aber die Quellkompilierung übersprungen und der Zielordner gelöscht wird, um die Verarbeitung zu beschleunigen und zu beschleunigen Verhindern Sie eine unerwünschte Schichtwechselerkennung für diesen Schritt.
- Quellcode-Kopie auf das Bild
- Packen Sie die Anwendung
Phase ausführen (JDK- oder JRE-Image):
- Kopieren Sie das Glas aus der vorherigen Phase
Hier zwei Beispiele.
a) Ein einfacher Weg ohne Cache für heruntergeladene Maven-Abhängigkeiten
Dockerfile:
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app
COPY pom.xml .
RUN mvn clean package -Dmaven.test.skip -Dmaven.main.skip -Dspring-boot.repackage.skip && rm -r target/
COPY src ./src
RUN mvn clean package -Dmaven.test.skip
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar
FROM openjdk:11.0-jre
WORKDIR /app
ARG DOCKER_PACKAGING_DIR=/app/target/docker-packaging
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/lib /app/lib
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/classes /app/classes
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/META-INF /app/META-INF
CMD java -cp .:classes:lib
Nachteil dieser Lösung? Alle Änderungen in der Datei pom.xml bedeuten, dass die gesamte Ebene, die die Maven-Abhängigkeiten herunterlädt und speichert, neu erstellt wird. Dies ist im Allgemeinen für Anwendungen mit vielen Abhängigkeiten nicht akzeptabel (und Spring Boot zieht viele Abhängigkeiten), insgesamt, wenn Sie während der Image-Erstellung keinen Maven-Repository-Manager verwenden.
b) Ein effizienterer Weg mit Cache für heruntergeladene Maven-Abhängigkeiten
Der Ansatz ist hier der gleiche, jedoch werden Downloads von Maven-Abhängigkeiten im Docker-Builder-Cache zwischengespeichert.
Die Cache-Operation basiert auf dem Buildkit (experimentelle API von Docker).
Um das Buildkit zu aktivieren, muss die env-Variable DOCKER_BUILDKIT = 1 festgelegt werden (Sie können dies tun, wo Sie möchten: .bashrc, Befehlszeile, Docker-Daemon-JSON-Datei ...).
Dockerfile:
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN --mount=type=cache,target=/root/.m2 mvn clean package -Dmaven.test.skip
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar
FROM openjdk:11.0-jre
WORKDIR /app
ARG DOCKER_PACKAGING_DIR=/app/target/docker-packaging
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/lib /app/lib
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/classes /app/classes
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/META-INF /app/META-INF
CMD java -cp .:classes:lib
mavenCentral()
in meinen Gradle-Abhängigkeiten durch ersetztmaven {url "http://nexus:8081..."
und bekomme jetzt nur noch Auflösungsprobleme.