(cd sample-java/helloworld && \
docker image build --quiet --tag javahello:mavenimage --file Dockerfile.01.mavenimage . )
sha256:16887bfdedb5c897ff7ae559a4ecd64b83310fe8fa2e11961ce773145612ffec
2024-10-02
Source | |
Branch |
|
Java |
|
Docker |
|
Cette partie illustre les différentes approches pour générer des images docker pour des applications Java.
Le plus simple est de s’appuyer sur une image de maven, d’y copier les sources et de donner comme commande le résutat de compilation.
FROM maven:3.9.0-eclipse-temurin-17-focal
WORKDIR /app
COPY pom.xml ./
RUN mvn dependency:resolve
COPY src ./src
RUN mvn clean verify
CMD mvn --quiet exec:java -Dexec.mainClass="fr.univtln.bruno.demos.docker.App"
# CMD java -jar target/*-jar-with-dependencies.jar
# CMD java -cp target/*-jar-with-dependencies.jar fr.univtln.bruno.demos.docker.App
(cd sample-java/helloworld && \
docker image build --quiet --tag javahello:mavenimage --file Dockerfile.01.mavenimage . )
sha256:16887bfdedb5c897ff7ae559a4ecd64b83310fe8fa2e11961ce773145612ffec
javahello mavenimage 16887bfdedb5 Less than a second ago 573MB
Il est plus efficace de s’appuyer sur la fabrication multistage d’une image docker pour séparer la chaîne de compilation de l’image d’exécution. On utilise alors comme image finale une base de JRE (donc plus légère) dans laquelle uniquement le résultat de la compilation est copié (attention, il doit inclure les dépendances cf. uberjar).
FROM maven:3.9.0-eclipse-temurin-17-focal as stage-build
WORKDIR /app
COPY pom.xml ./
RUN mvn dependency:resolve
COPY src ./src
RUN mvn clean verify
FROM eclipse-temurin:17-jre-jammy
COPY --from=stage-build /app/target/*-jar-with-dependencies.jar /myapp.jar
CMD ["java","-jar","/myapp.jar"]
(cd sample-java/helloworld && \
docker image build --quiet --tag javahello:mavenimagestage --file Dockerfile.02.mavenimagestage . )
sha256:ee4acfa81bd04ceb807dc42042ae77173b0cd8bccebdecb42e3482eff7550e04
javahello mavenimagestage ee4acfa81bd0 Less than a second ago 249MB
Les versions récentes de Docker proposent un mécanisme de cache qui permet de préciser explictement un dossier à mettre en cache lors du build d’une image. Pour Java et Maven, on peut ainsi mettre en cache ~/.m2
pour éviter de retélécharger systématiquement.
FROM maven:3.9.0-eclipse-temurin-17-focal as stage-build
WORKDIR /app
COPY . ./
RUN --mount=type=cache,target=/root/.m2 mvn clean verify
FROM eclipse-temurin:17-jre-jammy
COPY --from=stage-build /app/target/*-jar-with-dependencies.jar /myapp.jar
CMD ["java","-jar","/myapp.jar"]
(cd sample-java/helloworld && \
docker image build --quiet --tag javahello:cache --file Dockerfile.03.cache . )
sha256:4dd036700a92b691215f7ee9456c9c5ebebb8bb999486338a4195358d9e3da2e
javahello cache 4dd036700a92 Less than a second ago 249MB
Il est aussi possible de s’appuyer simplement sur l’image d’un JDK et d’utiliser un wrapper maven. Dans ce cas, la bonne version de maven sera téléchargée au moment de la compilation.
FROM eclipse-temurin:17-jdk-jammy as stage-build
WORKDIR /app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:resolve
COPY src ./src
RUN ./mvnw clean verify
FROM eclipse-temurin:17-jre-jammy
COPY --from=stage-build /app/target/*-jar-with-dependencies.jar /myapp.jar
CMD ["java","-jar","/myapp.jar"]
(cd sample-java/helloworld && \
docker image build --quiet --tag javahello:wrapper --file Dockerfile.04.wrapper . )
sha256:f865467f83e95aa2e39127112475128aa2182797b1078d25a037165e73eb5e68
javahello wrapper f865467f83e9 Less than a second ago 249MB
Il est aussi possible réaliser une chaine de compilation personnalisée à partir de zéro par exemple avec sdkman.
FROM ubuntu:jammy as stage-build
ARG JAVA_VERSION="17.0.6-tem"
ARG MAVEN_VERSION="3.9.0"
RUN apt-get update && \
apt-get install --yes --quiet --no-install-recommends ca-certificates curl zip unzip && \
curl -s "https://get.sdkman.io" | bash
SHELL ["/bin/bash", "-c"]
RUN source $HOME/.sdkman/bin/sdkman-init.sh && \
yes | sdk install java $JAVA_VERSION && \
yes | sdk install maven $MAVEN_VERSION && \
rm -rf $HOME/.sdkman/archives/* && \
rm -rf $HOME/.sdkman/tmp/*
WORKDIR /app
COPY . ./
RUN --mount=type=cache,target=/root/.m2 source $HOME/.sdkman/bin/sdkman-init.sh && \
mvn clean verify
FROM eclipse-temurin:17-jre-jammy
COPY --from=stage-build /app/target/*-jar-with-dependencies.jar /myapp.jar
CMD ["java","-jar","/myapp.jar"]
(cd sample-java/helloworld && \
docker image build --quiet --tag javahello:scratch --file Dockerfile.05.scratch . )
sha256:fb9e66c7f373395ba2742eda2a0c9df9112fb31fb2cb5c79a5050f21a7789a4c
javahello scratch fb9e66c7f373 1 second ago 249MB
La meilleure solution est d’utiliser les modules de Java et jlink pour produire une livraison minimale du JRE et des dépendances pour le projet.
TODO
javahello scratch fb9e66c7f373 1 second ago 249MB
javahello wrapper f865467f83e9 50 seconds ago 249MB
javahello cache 4dd036700a92 About a minute ago 249MB
javahello mavenimagestage ee4acfa81bd0 About a minute ago 249MB
javahello mavenimage 16887bfdedb5 2 minutes ago 573MB