Jak zadokeryzować projekt Maven? i na ile sposobów to osiągnąć?

87

Jestem nowy w Dockerze i nie wiem, jak uruchomić projekt Java z maven, mimo że przeczytałem wiele dokumentów i wypróbowałem wiele metod.

  1. Czy powinienem zbudować obraz za pomocą Dockerfile?
  2. Jakie są polecenia podczas uruchamiania projektu maven na hoście Dockerfile?
Yashon Lin
źródło

Odpowiedzi:

122

Przykład roboczy.

To nie jest samouczek dotyczący uruchamiania na wiosnę. To zaktualizowana odpowiedź na pytanie, jak uruchomić kompilację Mavena w kontenerze Dockera.

Pytanie pierwotnie wysłane 4 lata temu.

1. Wygeneruj aplikację

Użyj inicjatora wiosny, aby wygenerować aplikację demonstracyjną

https://start.spring.io/

wprowadź opis obrazu tutaj

Rozpakuj archiwum zip lokalnie

2. Utwórz plik Dockerfile

#
# Build stage
#
FROM maven:3.6.0-jdk-11-slim AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package

#
# Package stage
#
FROM openjdk:11-jre-slim
COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"]

Uwaga

  • W tym przykładzie zastosowano kompilację wieloetapową . Pierwszy etap służy do budowania kodu. Drugi etap zawiera tylko zbudowany plik jar i środowisko JRE do jego uruchomienia (zwróć uwagę, jak plik jar jest kopiowany między etapami).

3. Zbuduj obraz

docker build -t demo .

4. Uruchom obraz

$ docker run --rm -it demo:latest

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-02-22 17:18:57.835  INFO 1 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT on f4e67677c9a9 with PID 1 (/usr/local/bin/demo.jar started by root in /)
2019-02-22 17:18:57.837  INFO 1 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2019-02-22 17:18:58.294  INFO 1 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.711 seconds (JVM running for 1.035)

Różne

Przeczytaj dokumentację centrum Docker, w jaki sposób można zoptymalizować kompilację Maven, aby używać lokalnego repozytorium do buforowania plików JAR.

Aktualizacja (2019-02-07)

To pytanie ma już 4 lata i można śmiało powiedzieć, że budowanie aplikacji za pomocą Dockera przeszło znaczną zmianę.

Opcja 1: Kompilacja wieloetapowa

Ten nowy styl umożliwia tworzenie lżejszych obrazów, które nie obejmują narzędzi do kompilacji ani kodu źródłowego.

Poniższy przykład ponownie wykorzystuje oficjalny obraz podstawowy Mavena do uruchomienia pierwszego etapu kompilacji przy użyciu żądanej wersji Mavena. Druga część pliku określa, w jaki sposób zbudowany plik jar jest montowany w ostatecznym obrazie wyjściowym.

FROM maven:3.5-jdk-8 AS build  
COPY src /usr/src/app/src  
COPY pom.xml /usr/src/app  
RUN mvn -f /usr/src/app/pom.xml clean package

FROM gcr.io/distroless/java  
COPY --from=build /usr/src/app/target/helloworld-1.0.0-SNAPSHOT.jar /usr/app/helloworld-1.0.0-SNAPSHOT.jar  
EXPOSE 8080  
ENTRYPOINT ["java","-jar","/usr/app/helloworld-1.0.0-SNAPSHOT.jar"]  

Uwaga:

  • Używam bezproblemowego obrazu podstawowego Google , który stara się zapewnić wystarczający czas działania dla aplikacji Java.

Opcja 2: wysięgnik

Nie korzystałem z tego podejścia, ale wydaje mi się, że warto go zbadać, ponieważ umożliwia tworzenie obrazów bez konieczności tworzenia nieprzyjemnych rzeczy, takich jak Dockerfiles :-)

https://github.com/GoogleContainerTools/jib

Projekt ma wtyczkę Maven, która integruje pakowanie twojego kodu bezpośrednio z przepływem pracy Maven.


Oryginalna odpowiedź (uwzględniona w celu zapewnienia kompletności, ale napisana przed wiekami)

Spróbuj użyć nowych oficjalnych obrazów, jest jeden dla Mavena

https://registry.hub.docker.com/_/maven/

Obraz może służyć do uruchamiania Mavena w czasie kompilacji w celu utworzenia skompilowanej aplikacji lub, jak w poniższych przykładach, do uruchomienia kompilacji Maven w kontenerze.

Przykład 1 - Maven działający w kontenerze

Następujące polecenie uruchamia kompilację Mavena wewnątrz kontenera:

docker run -it --rm \
       -v "$(pwd)":/opt/maven \
       -w /opt/maven \
       maven:3.2-jdk-7 \
       mvn clean install

Uwagi:

  • Zaletą tego podejścia jest to, że całe oprogramowanie jest instalowane i uruchamiane w kontenerze. Potrzebujesz tylko dockera na komputerze hosta.
  • Zobacz Dockerfile dla tej wersji

Przykład 2 - Użyj Nexusa do buforowania plików

Uruchom kontener Nexus

docker run -d -p 8081:8081 --name nexus sonatype/nexus

Utwórz plik „settings.xml”:

<settings>
  <mirrors>
    <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://nexus:8081/content/groups/public/</url>
    </mirror>
  </mirrors>
</settings>

Teraz uruchom Maven łączący się z kontenerem Nexusa, aby zależności zostały zapisane w pamięci podręcznej

docker run -it --rm \
       -v "$(pwd)":/opt/maven \
       -w /opt/maven \
       --link nexus:nexus \
       maven:3.2-jdk-7 \
       mvn -s settings.xml clean install

Uwagi:

  • Zaletą uruchamiania Nexusa w tle jest to, że repozytoriami innych firm można zarządzać przez adres URL administratora w sposób przejrzysty dla kompilacji Mavena działających w lokalnych kontenerach.
Mark O'Connor
źródło
czy można to wykorzystać do zastąpienia centrali Maven w kompilacji gradle? jak stwierdzono w support.sonatype.com/entries/ ... Zastąpiłem mavenCentral()w moich zależnościach gradle maven {url "http://nexus:8081..."i teraz pojawiają się problemy z rozwiązaniem.
mohamnag
@mohamnag Prawidłowo, powyższy plik "ustawień" Mavena robi dokładnie to, przekierowując wszystkie żądania Maven Central do lokalnego repozytorium nexusa. Musisz opisać, jakie masz problemy z rozdzielczością. Może być cokolwiek ... Na przykład, czy skonfigurowałeś łącze Docker, aby host „nexus” został poprawnie rozwiązany?
Mark O'Connor
Okazało się, że wszystko jest w porządku, ale nexus albo potrzebował czasu na zbudowanie indeksu, albo coś innego spowodowało kłopoty. Próbowałem też wyzwolić aktualizację indeksu, dlatego nie jestem pewien, który przypadek rozwiązał problem. Jednak dzięki.
mohamnag,
Nexus 3 jest teraz dostępny również jako kontener docker. Użyj „sonatype / nexus3”
Thorbjørn Ravn Andersen
1
@avandeursen Masz rację, że parametr --link jest przestarzały (odpowiedź ma ponad 3 lata). Jednak bardziej poprawnym rozwiązaniem (moim zdaniem) jest stworzenie sieci dockerowej i uruchomienie na niej obu kontenerów. W ten sposób możesz wykorzystać natywną funkcję DNS w Dockerze i nadal odwoływać się do kontenera Nexusa według nazwy. Zaktualizuję przykład później
Mark O'Connor
47

Sposobów może być wiele. Ale wdrożyłem je na dwa sposoby

Podany przykład dotyczy projektu maven.

1. Korzystanie z Dockerfile w projekcie maven

Użyj następującej struktury plików:

Demo
└── src
|    ├── main
|    │   ├── java
|    │       └── org
|    │           └── demo
|    │               └── Application.java
||    └── test
|
├──── Dockerfile
├──── pom.xml

I zaktualizuj plik Dockerfile jako:

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

Przejdź do folderu projektu i wpisz następujące polecenie, dzięki któremu będziesz mógł utworzyć obraz i uruchomić ten obraz:

$ mvn clean
$ mvn install
$ docker build -f Dockerfile -t springdemo .
$ docker run -p 8080:8080 -t springdemo

Pobierz wideo w Spring Boot za pomocą Dockera

2. Korzystanie z wtyczek Maven

Dodaj daną wtyczkę maven pom.xml

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.4.5</version>
        <configuration>
            <imageName>springdocker</imageName>
            <baseImage>java</baseImage>
            <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
            <resources>
                <resource>
                    <targetPath>/</targetPath>
                    <directory>${project.build.directory}</directory>
                    <include>${project.build.finalName}.jar</include>
                </resource>
            </resources>
        </configuration>
    </plugin>

Przejdź do folderu projektu i wpisz następujące polecenie, aby utworzyć obraz i uruchomić ten obraz:

$ mvn clean package docker:build
$ docker images
$ docker run -p 8080:8080 -t <image name>

W pierwszym przykładzie tworzymy plik Dockerfile i udostępniamy obraz bazowy i dodajemy jar i so, po wykonaniu tej czynności uruchomimy polecenie docker, aby zbudować obraz o określonej nazwie, a następnie uruchomimy ten obraz.

Natomiast w drugim przykładzie używamy Maven plugin w którym dostarczanie baseImagea imageNamewięc nie ma potrzeby tworzenia Dockerfile tutaj .. po zapakowaniu Maven projekt otrzymamy obraz Döcker i po prostu trzeba uruchomić ten obraz ..

Riddhi Gohil
źródło
Zamiast modyfikować punkt wejścia, aby określić nazwę artefaktu, możesz użyć podejścia takiego jak tutaj: alooma.com/blog/building-dockers - użyj wtyczki maven-dependency-plugin, aby użyć wspólnej nazwy. Nie ma potrzeby umieszczania wersjonowanego pliku jar w kontenerze platformy Docker, ponieważ sam kontener jest wersjonowany.
kboom
14

Z reguły powinieneś zbudować gruby plik JAR przy użyciu Maven (JAR, który zawiera zarówno twój kod, jak i wszystkie zależności).

Następnie możesz napisać plik Dockerfile, który odpowiada Twoim wymaganiom (jeśli możesz zbudować gruby JAR, potrzebujesz tylko podstawowego systemu operacyjnego, takiego jak CentOS i JVM).

Właśnie tego używam w przypadku aplikacji Scala (opartej na Javie).

FROM centos:centos7

# Prerequisites.

RUN yum -y update
RUN yum -y install wget tar

# Oracle Java 7

WORKDIR /opt

RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u71-b14/server-jre-7u71-linux-x64.tar.gz
RUN tar xzf server-jre-7u71-linux-x64.tar.gz
RUN rm -rf server-jre-7u71-linux-x64.tar.gz
RUN alternatives --install /usr/bin/java java /opt/jdk1.7.0_71/bin/java 1

# App

USER daemon

# This copies to local fat jar inside the image
ADD /local/path/to/packaged/app/appname.jar /app/appname.jar

# What to run when the container starts
ENTRYPOINT [ "java", "-jar", "/app/appname.jar" ]

# Ports used by the app
EXPOSE 5000

Tworzy to obraz oparty na CentOS z Java7. Po uruchomieniu wykona plik jar aplikacji.

Najlepszym sposobem na wdrożenie jest za pośrednictwem rejestru Docker, jest to jak Github dla obrazów Dockera.

Możesz zbudować taki obraz:

# current dir must contain the Dockerfile
docker build -t username/projectname:tagname .

Następnie możesz przesłać obraz w ten sposób:

docker push username/projectname # this pushes all tags

Gdy obraz znajdzie się w rejestrze Docker, możesz go pobrać z dowolnego miejsca na świecie i uruchomić.

Aby uzyskać więcej informacji, zobacz Podręcznik użytkownika platformy Docker .

Coś, o czym należy pamiętać :

Możesz również wciągnąć repozytorium do obrazu i zbudować jar jako część wykonania kontenera, ale nie jest to dobre podejście, ponieważ kod może się zmienić i możesz skończyć z użyciem innej wersji aplikacji bez powiadomienia.

Zbudowanie słoika na tłuszcz rozwiązuje ten problem.

Matteo Pacini
źródło
Cześć, użyłem twojego przykładu w moim pliku docker, aby skopiować słoik tłuszczu z obrazu, ale kompilacja nie powiodła się, ponieważ nie mogłem znaleźć słoika tłuszczu, podając ścieżkę lokalną. Czy jest to coś w rodzaju target / app.jar?
user_mda,
Cześć, czy jest sposób, aby pobrać artefakt z Nexusa w czasie wykonywania? Aby określić artefakt do pobrania przy użyciu właściwości, a nie faktycznego łącza do samego pliku jar? W pliku dockerfile: RUN wget -O {project.build.finalname}.jar ale chcę pobrać powyższy plik jar z nexusa.
Pramod Setlur
1
Dołączanie pliku FAT JAR do repozytorium kodu jest dla mnie powolne. Czy jest jakiś sposób na użycie mavena do zbudowania obrazu?
WoLfPwNeR
1
Tłuste słoiki też mają pewne problemy, szczególnie w przypadku słoików z podpisem.
Thorbjørn Ravn Andersen
1
Z reguły nigdy nie używaj fat jar, pakiety, które opierają się na manifeście lub innych plikach danych w ich jar, mogą zawieść, ponieważ nie ma bezpiecznego sposobu na połączenie tych danych. Pliki manifestu z pasującymi ścieżkami w konflikcie jar i pierwsze lub ostatnie wygrane (nie pamiętam które). Jedynym przypadkiem, w którym powinieneś rozważyć użycie fat jar, jest sytuacja, w której masz bardzo ograniczony zestaw zależności i dobrze wiesz, że ich słoiki nie zawierają sprzecznych danych manifestu. W przeciwnym razie zachowaj bezpieczeństwo, używając słoików, ponieważ zostały zaprojektowane do użytku (tj. Oddzielnie).
PiersyP
3

Oto mój wkład.
Nie będę próbował wymieniać wszystkich narzędzi / bibliotek / wtyczek, które istnieją, aby skorzystać z Dockera z Mavenem. Niektóre odpowiedzi już to zrobiły.
zamiast tego skupię się na typologii aplikacji i sposobie Dockerfile.
Dockerfilejest naprawdę prostą i ważną koncepcją Dockera (wszystkie znane / publiczne obrazy opierają się na tym) i myślę, że próba uniknięcia zrozumienia i używania Dockerfiles niekoniecznie jest lepszym sposobem na wejście w świat Dockera.

Dokeryzowanie aplikacji zależy od samej aplikacji i celu do osiągnięcia

1) W przypadku aplikacji, które chcemy dalej uruchamiać na zainstalowanym / samodzielnym serwerze Java (Tomcat, JBoss itp.)

Droga jest trudniejsza i nie jest to idealny cel, ponieważ zwiększa złożoność (musimy zarządzać / utrzymywać serwer) i jest mniej skalowalny i mniej szybki niż serwery wbudowane pod względem budowania / wdrażania / niewydrażania.
Ale w przypadku starszych aplikacji można to uznać za pierwszy krok.
Generalnie chodzi o zdefiniowanie obrazu Docker dla serwera i zdefiniowanie obrazu dla aplikacji do wdrożenia.
Obrazy dockera dla aplikacji generują oczekiwane WAR / EAR, ale nie są one wykonywane jako kontener, a obraz aplikacji serwerowej wdraża komponenty utworzone przez te obrazy jako wdrożone aplikacje.
W przypadku ogromnych aplikacji (miliony linii kodów) z wieloma starszymi elementami i tak trudnych do migracji do pełnego rozwiązania wbudowanego w rozruchu sprężynowym, jest to naprawdę niezła poprawa.
Nie będę szczegółowo opisywał tego podejścia, ponieważ dotyczy to drobnych przypadków użycia Dockera, ale chciałem ujawnić ogólną ideę tego podejścia, ponieważ myślę, że dla programistów zajmujących się tymi złożonymi przypadkami dobrze jest wiedzieć, że niektóre drzwi są otwarte dla zintegrować Docker.

2) W przypadku aplikacji, które same osadzają / uruchamiają serwer (Spring Boot z wbudowanym serwerem: Tomcat, Netty, Jetty ...)

To idealny cel w przypadku Dockera . Wybrałem Spring Boot, ponieważ jest to naprawdę fajny framework do tego, który ma również bardzo wysoki poziom utrzymania, ale teoretycznie moglibyśmy użyć dowolnego innego sposobu Java, aby to osiągnąć.
Generalnie chodzi o to, aby zdefiniować obraz platformy Docker na aplikację do wdrożenia.
Obrazy dockera dla aplikacji tworzą plik JAR lub zestaw plików JAR / classes / configuration, a te uruchamiają maszynę JVM z aplikacją (polecenie java), gdy tworzymy i uruchamiamy kontener z tych obrazów.
W przypadku nowych aplikacji lub aplikacji, które nie są zbyt skomplikowane do migracji, ten sposób musi być preferowany w stosunku do samodzielnych serwerów, ponieważ jest to standardowy i najbardziej efektywny sposób korzystania z kontenerów.
Opiszę szczegółowo to podejście.

Dokeryzowanie aplikacji maven

1) Bez butów sprężynowych

Chodzi o to, aby utworzyć fat jar z Mavenem (wtyczką asemblera maven i pomoc dla wtyczki maven shadow), która zawiera zarówno skompilowane klasy aplikacji, jak i potrzebne zależności maven.
Następnie możemy zidentyfikować dwa przypadki:

  • jeśli aplikacja jest aplikacją desktopową lub autonomiczną (która nie musi być wdrażana na serwerze): możemy określić, jak CMD/ENTRYPOINTw przypadku Dockerfilewykonania aplikacji w języku Java:java -cp .:/fooPath/* -jar myJar

  • jeśli aplikacja jest aplikacją serwerową, na przykład Tomcat, idea jest taka sama: pobrać gruby plik aplikacji i uruchomić JVM w CMD/ENTRYPOINT. Ale tutaj z ważną różnicą: musimy uwzględnić pewną logikę i określone biblioteki ( org.apache.tomcat.embedbiblioteki i kilka innych), które uruchamiają wbudowany serwer po uruchomieniu głównej aplikacji.
    Mamy obszerny przewodnik po stronie heroku .
    W pierwszym przypadku (aplikacja autonomiczna) jest to prosty i skuteczny sposób korzystania z Dockera.
    W drugim przypadku (aplikacja serwerowa), który działa, ale nie jest prosty, może być podatny na błędy i nie jest modelem bardzo rozszerzalnym, ponieważ nie umieszczasz aplikacji w ramie dojrzałej struktury, takiej jak Spring Boot, która wykonuje wiele tych rzeczy dla Ciebie, a także zapewnia wysoki poziom rozszerzenia.
    Ma to jednak zaletę: masz wysoki poziom swobody, ponieważ używasz bezpośrednio wbudowanego interfejsu Tomcat API.

2) Z butem sprężynowym

Wreszcie zaczynamy.
Jest to proste, wydajne i bardzo dobrze udokumentowane.
Istnieje naprawdę kilka podejść, aby aplikacja Maven / Spring Boot działała na platformie Docker.
Odsłanianie ich wszystkich byłoby długie i może nudne.
Najlepszy wybór zależy od Twoich wymagań.
Ale niezależnie od sposobu, strategia kompilacji pod względem warstw dockera wygląda tak samo.
Chcemy użyć kompilacji wieloetapowej: jednej polegającej na Maven do rozwiązywania zależności i do kompilacji, a drugiej polegającej na JDK lub JRE do uruchamiania aplikacji.

Scena budowy (obraz Mavena):

  • kopia pom do obrazu
  • zależności i pobieranie wtyczek.
    O tym, mvn dependency:resolve-pluginsprzykuty do mvn dependency:resolvemoże wykonać swoją pracę, ale nie zawsze.
    Czemu ? Ponieważ te wtyczki i packagewykonanie do pakowania słoika tłuszczu mogą opierać się na różnych artefaktach / wtyczkach, a nawet na tym samym artefakcie / wtyczce, mogą one nadal pobierać inną wersję. Tak więc bezpieczniejszym podejściem, chociaż potencjalnie wolniejszym, jest rozwiązywanie zależności przez wykonanie dokładnie mvnpolecenia używanego do spakowania aplikacji (które ściągnie dokładnie zależności, których potrzebujesz), ale pomijając kompilację źródłową i usuwając folder docelowy, aby przyspieszyć przetwarzanie i zapobiec wykryciu niepożądanej zmiany warstwy na tym etapie.
  • kopia kodu źródłowego do obrazu
  • spakuj aplikację

Uruchom etap (obraz JDK lub JRE):

  • skopiuj słoik z poprzedniego etapu

Oto dwa przykłady.

a) Prosty sposób bez pamięci podręcznej dla pobranych zależności maven

Dockerfile:

########Maven build stage########
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app

#copy pom
COPY pom.xml .

#resolve maven dependencies
RUN mvn clean package -Dmaven.test.skip -Dmaven.main.skip -Dspring-boot.repackage.skip && rm -r target/

#copy source
COPY src ./src

# build the app (no dependency download here)
RUN mvn clean package  -Dmaven.test.skip

# split the built app into multiple layers to improve layer rebuild
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar

########JRE run stage########
FROM openjdk:11.0-jre
WORKDIR /app

#copy built app layer by layer
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

#run the app
CMD java -cp .:classes:lib/* \
         -Djava.security.egd=file:/dev/./urandom \
         foo.bar.MySpringBootApplication

Wada tego rozwiązania? Wszelkie zmiany w pom.xml oznaczają ponowne utworzenie całej warstwy, która pobiera i przechowuje zależności maven. Jest to generalnie niedopuszczalne w przypadku aplikacji z wieloma zależnościami (a Spring Boot ściąga wiele zależności), ogólnie rzecz biorąc, jeśli nie używasz menedżera repozytorium maven podczas budowania obrazu.

b) Bardziej efektywny sposób z pamięcią podręczną dla pobranych zależności maven

Podejście jest tutaj takie samo, ale pobieranie zależności maven, które są buforowane w pamięci podręcznej narzędzia docker builder.
Operacja pamięci podręcznej opiera się na buildkicie (eksperymentalnym interfejsie API dockera).
Aby włączyć buildkit, należy ustawić zmienną env DOCKER_BUILDKIT = 1 (możesz to zrobić gdzie chcesz: .bashrc, wiersz poleceń, plik json demona Dockera ...).

Dockerfile:

# syntax=docker/dockerfile:experimental

########Maven build stage########
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app

#copy pom
COPY pom.xml .

#copy source
COPY src ./src

# build the app (no dependency download here)
RUN --mount=type=cache,target=/root/.m2  mvn clean package -Dmaven.test.skip

# split the built app into multiple layers to improve layer rebuild
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar

########JRE run stage########
FROM openjdk:11.0-jre
WORKDIR /app

#copy built app layer by layer
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

#run the app
CMD java -cp .:classes:lib/* \
         -Djava.security.egd=file:/dev/./urandom \
         foo.bar.MySpringBootApplication
davidxxx
źródło