webentwicklung-frage-antwort-db.com.de

So erstellen Sie einen Docker-Container für eine Java-App

Ich möchte ein Docker-Image für meine Java-Anwendung erstellen. Die folgenden Überlegungen sollten jedoch für die meisten kompilierten Sprachen zutreffen.

problem

Auf meinem Build-Server möchte ich ein Docker-Image für meine Anwendung als lieferbares Produkt erstellen. Dazu muss ich die Anwendung mit einem Build-Tool (normalerweise Gradle, Maven oder Ant) kompilieren und dann die erstellte JAR-Datei zum Docker-Image hinzufügen. Da ich möchte, dass das Docker-Image nur die JAR-Datei ausführt, beginne ich natürlich mit einem Basis-Image, auf dem Java bereits installiert ist.

Es gibt drei Möglichkeiten, dies zu tun:

lassen Sie das Build-Tool den Prozess steuern

In diesem Fall steuert mein Build-Tool den gesamten Prozess. Es bereitet also die JAR-Datei vor und ruft nach dem Erstellen des JAR Docker auf, um das Image zu erstellen. Dies funktioniert, da der JAR zuvor erstellt wurde und Docker den Erstellungsprozess zum Erstellen des JAR nicht kennt.

Aber meine Dockerfile ist nicht mehr eigenständig. Es hängt von den Schritten ab, die außerhalb von Docker ausgeführt werden müssen. In meiner Docker-Datei habe ich eine COPY- oder ADD-Anweisung, die die JAR-Datei in das Image kopieren soll. Diese Anweisung schlägt fehl, wenn die Dose nicht zuvor erstellt wurde. Das Ausführen der Docker-Datei funktioniert möglicherweise nicht. Dies wird zu einem Problem, wenn Sie Dienste integrieren möchten, die nur mit der aktuellen Docker-Datei erstellt werden, z. B. der Auto-Build-Funktion von DockerHub.

lassen Sie Docker den Build steuern

In diesem Fall werden alle erforderlichen Schritte zum Erstellen des Images zur Dockerfile hinzugefügt, sodass das Image durch einfaches Ausführen des Docker-Builds erstellt werden kann.

Das Hauptproblem bei diesem Ansatz besteht darin, dass es nicht möglich ist, Befehle zu einer Dockerfile hinzuzufügen, die außerhalb des erstellten Docker-Images ausgeführt werden sollten. Das heißt, ich muss meinen Quellcode und meine Build-Tools zum Docker-Image hinzufügen und meine JAR-Datei im Image erstellen. Dies führt dazu, dass mein Image größer wird, als es aufgrund der hinzugefügten Dateien ist, die zur Laufzeit nicht erforderlich sind. Dadurch werden meinem Bild auch zusätzliche Ebenen hinzugefügt.

Bearbeiten:

Da @ adrian-mouat darauf hinwies, wenn ich die Quellen hinzufügen, die Anwendung erstellen und die Quellen in einer RUN-Anweisung löschen würde, könnte ich das Hinzufügen von unnötigen Dateien und Ebenen zum Docker-Image vermeiden. Dies würde bedeuten, einen wahnsinnig verketteten Befehl zu erstellen. 

zwei separate Builds

In diesem Fall teilen wir unseren Build in zwei Teile auf: Zuerst erstellen wir die JAR-Datei mit unserem Build-Tool und laden sie in ein Repository (Maven- oder Ivy-Repository) hoch. Wir lösen dann einen separaten Docker-Build aus, der nur die JAR-Datei aus dem Repository hinzufügt.

fazit

Meiner Meinung nach wäre der bessere Weg das Build-Tool den Prozess steuern lassen . Dies führt zu einem sauberen Docker-Image. Da das Image das ist, was wir liefern wollen, ist dies von Bedeutung. Um zu vermeiden, dass eine möglicherweise nicht funktionierende Docker-Datei herumliegt, sollte diese als Teil des Builds erstellt werden. Daher würde niemand versehentlich einen defekten Build starten.

Dies erlaubt mir jedoch nicht, mich mit DockerHub zu integrieren.

frage

Gibt es eine andere Möglichkeit, wie ich vermisse?

37
Tobias Kremer

Der Docker-Registrierungshub verfügt über ein Maven-Image , mit dem Java-Container erstellt werden können.

Bei diesem Ansatz muss auf der Build-Maschine weder Java noch Maven vorinstalliert sein. Docker steuert den gesamten Build-Prozess.

Beispiel

├── Dockerfile
├── pom.xml
└── src
    ├── main
    │   ├── Java
    │   │   └── org
    │   │       └── demo
    │   │           └── App.Java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── Java
            └── org
                └── demo
                    └── AppTest.Java

Container ist wie folgt aufgebaut:

docker build -t my-maven .

Und wie folgt laufen:

$ docker run -it --rm my-maven
0    [main] INFO  org.demo.App  - hello world

Dockerfile

FROM maven:3.3-jdk-8-onbuild
CMD ["Java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

Aktualisieren

Wenn Sie Ihren Container optimieren möchten, um die Quelle auszuschließen, können Sie eine Docker-Datei erstellen, die nur die erstellte jar enthält:

FROM Java:8
ADD target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar
CMD ["Java","-jar","/opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

Und bauen Sie den Container in zwei Schritten auf:

docker run -it --rm -w /opt/maven \
   -v $PWD:/opt/maven \
   -v $HOME/.m2:/root/.m2 \
   maven:3.3-jdk-8 \
   mvn clean install

docker build -t my-app .

__

Update (2017-07-27)

Docker verfügt jetzt über eine mehrstufige Build Fähigkeit. Dadurch kann Docker einen Container mit einem Image erstellen, das die Build-Tools enthält, aber ein Image nur mit den Laufzeitabhängigkeiten ausgeben. 

Das folgende Beispiel veranschaulicht dieses Konzept. Beachten Sie, wie die JAR-Datei aus dem Zielverzeichnis der ersten Erstellungsphase kopiert wird

FROM maven:3.3-jdk-8-onbuild 

FROM Java:8
COPY --from=0 /usr/src/app/target/demo-1.0-SNAPSHOT.jar /opt/demo.jar
CMD ["Java","-jar","/opt/demo.jar"]
25
Mark O'Connor

Struktur der Java-Anwendung

Demo
└── src
|    ├── main
|    │   ├── Java
|    │   │   └── org
|    │   │       └── demo
|    │   │           └── App.Java
|    │   └── resources
|    │       └── application.properties
|    └── test
|         └── Java
|               └── org
|                   └── demo
|                         └── App.Java  
├──── Dockerfile
├──── pom.xml

Inhalt von Dockerfile

FROM Java:8
EXPOSE 8080
ADD /target/demo.jar demo.jar
ENTRYPOINT ["Java","-jar","demo.jar"]

Befehle zum Erstellen und Ausführen von Image

  • Wechseln Sie in das Verzeichnis des Projekts. Lassen Sie uns D:/Demo sagen
$ cd D/demo
$ mvn clean install
$ docker build demo .
$ docker run -p 8080:8080 -t demo

Prüfen Sie, ob der Container läuft oder nicht

$ docker ps

Die Ausgabe wird sein

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
55c11a464f5a        demo1               "Java -jar demo.jar"   21 seconds ago      Up About a minute   0.0.0.0:8080->8080/tcp   cranky_mayer
5
Riddhi Gohil

Am einfachsten geht es mit das Build-Tool den Prozess steuern lassen. Andernfalls müssten Sie die Build-Datei Ihres Build-Tools (wie pom.xml für Maven oder build.gradle für Gradle) sowie eine Dockerfile-Datei verwalten.

Ein einfacher Weg, um einen Docker-Container für Ihre Java-App zu erstellen, ist die Verwendung von Jib , das als Maven und Gradle plugins verfügbar ist.

Wenn Sie beispielsweise Maven verwenden und Ihren Container zu Ihrem laufenden Docker-Dämon erstellen möchten, können Sie einfach diesen Befehl ausführen:

mvn compile com.google.cloud.tools:jib-maven-plugin:0.9.2:dockerBuild

Sie können auch direkt in eine Docker-Registry einbauen mit Jib , ohne docker installieren zu müssen, einen Docker-Daemon auszuführen (der Rootberechtigungen erfordert) oder eine Dockerfile zu schreiben. Es ist auch schneller und erstellt Bilder reproduzierbar.

Weitere Informationen zu Jib finden Sie im Github-Repo: https://github.com/GoogleContainerTools/jib

2
Qingyang Chen

Einige Sachen:

  • Wenn Sie Dateien in derselben Anweisung löschen, in der Sie sie hinzufügen, beanspruchen sie keinen Platz im Bild. Wenn Sie sich einige Dockerfiles für die offiziellen Bilder ansehen, werden Sie sehen, dass sie den Quellcode herunterladen, erstellen und in demselben Schritt löschen (zB https://github.com/docker-library/python/blob/0fa3202789648132971160f686f5a37595108f44 /3.5/slim/Dockerdatei ). Dies bedeutet, dass Sie einige lästige Gymnastik machen müssen, aber es ist durchaus machbar.

  • Ich sehe das Problem nicht mit zwei separaten Dockerfiles. Das Schöne daran ist, dass Sie die JRE anstelle der JDK verwenden können, um Ihr Glas zu hosten.

1
Adrian Mouat

es gibt alternative Verwendungsmöglichkeiten für die Ausführung von Jar- oder Kriegspaketen

  • fügen Sie dem Bild ein Glas hinzu. 
  • heapsize für Java festlegen 
  • jar-Befehl über Einstiegspunkt ausführen

beispiel Dockerfile

FROM base
ADD sample.jar renamed.jar
ENV HEAP_SIZE 256m
ENTRYPOINT exec Java -Xms$HEAP_SIZE -Xmx$HEAP_SIZE -jar renamed.jar

zusätzlich Paketbereitstellungsbeispiel auf Tomcat 

FROM Tomcat7
ADD sample.war ${CATALINA_HOME}/webapps/ROOT.war
CMD ${CATALINA_HOME}/bin/catalina.sh run

Erstellen von Dockerfiles als Bild

cp Tomcat.dockerfile /workingdir/Dockerfile
docker build -t name /workingdir/Dockerfile .

Bilder auflisten 

docker images

Verwenden Sie image, um einen Container zu erstellen

docker run --name cont_name --extra-vars var1=val1 var2=val2 imagename
0
pmoksuz

Containerisieren Sie Ihre Java -Anwendung mit dem Jib-Tool, ohne Dockerfile zu schreiben

Jib ist ein Open-Source-Tool Java, das von Google zum Erstellen von Docker-Images von Java - Anwendungen verwaltet wird. Dies vereinfacht die Containerisierung, da wir keine Docker-Datei schreiben müssen . Tatsächlich muss nicht einmal Docker installiert sein , um die Docker-Images selbst zu erstellen und zu veröffentlichen.

Google veröffentlicht Jib sowohl als Maven- als auch als Gradle-Plugin. https://github.com/GoogleContainerTools/jib

Containerisieren Sie Ihre Java -Anwendung mit dem Maven-Projekt

https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#quickstart

Containerisieren Sie Ihre Java -Anwendung mit Gradle-Projekt

https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#quickstart

0
anandchaugule

Hier Ich beschreibe, wie ich das in meiner Entwicklungsumgebung mache. 

  • Baue den Krieg/das Glas lokal mit Maven 
  • Kopieren Sie es in einen lokalen Docker-Ordner
  • Führen Sie Intellij Docker plugin aus , um ein Docker-Image zu erstellen, das die War/jar-Datei enthält, den Anwendungsserver auszuführen und auf dem Remote-Docker-Server bereitzustellen

Ich hoffe es hilft.

0
Eyal.Dahari

Wir haben das Spotify Docker Maven Plugin eine Zeit lang verwendet. Mit dem Plugin können Sie einen Docker Build an eine Phase des Maven-Lebenszyklus binden.

Ein Beispiel: Führen Sie den Docker-Build nach dem Paketieren (phase: package) Ihrer Anwendung aus, indem Sie das Plugin so konfigurieren, dass Ihre erstellte Anwendung dem Docker-Build-Kontext als Ressource hinzugefügt wird. Führen Sie in der Bereitstellungsphase das Docker Push-Ziel aus, um Ihr Docker-Image in eine Registrierung zu verschieben. Dies kann neben dem normalen Implementierungs-Plugin ausgeführt werden, das das Artefakt in einem Repository wie Nexus veröffentlicht.

Später haben wir den Build in zwei separate Jobs auf dem CI-Server aufgeteilt. Da Docker nur eine Möglichkeit zum Ausführen Ihrer Anwendung ist (manchmal benötigen wir die freigegebene Anwendung in verschiedenen Umgebungen und nicht nur Docker), sollte der Maven-Build nicht auf Docker angewiesen sein.

Der erste Job gibt die Anwendung in Nexus frei (über Maven deploy). Der zweite Job (der eine Downstream-Abhängigkeit des ersten Jobs sein kann) lädt das neueste Release-Artefakt herunter, führt den Docker-Build durch und überträgt das Image in die Registry. Um die neueste Version herunterzuladen, verwenden wir das Versions Maven Plugin (Versionen: use-latest-Releases) sowie das Maven Dependency Plugin (Abhängigkeit: get und Abhängigkeit: Kopie).

Der zweite Job kann auch für eine bestimmte Version der Anwendung gestartet werden, um das Docker-Image für eine ältere Version (neu) zu erstellen. Außerdem können Sie eine Build-Pipeline (auf Jenkins) verwenden, die beide Jobs ausführt und die Release-Version oder das Release-Artefakt an den Docker-Build übergibt.

0
gclaussn