java - hub - mvn package docker build
Dependencias de caché de docker de Maven (6)
Estoy tratando de usar la ventana acoplable para automatizar las construcciones de Maven. El proyecto que quiero construir demora casi 20 minutos en descargar todas las dependencias, así que intenté crear una imagen de ventana acoplable que almacene en caché estas dependencias, pero parece que no las guarda. Mi Dockerfile es
FROM maven:alpine
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD pom.xml /usr/src/app
RUN mvn dependency:go-offline
La imagen se construye, y descarga todo. Sin embargo, la imagen resultante es del mismo tamaño que la imagen básica de maven:alpine
, por lo que no parece haber guardado en caché las dependencias de la imagen. Cuando trato de usar la imagen para mvn compile
, pasa por los 20 minutos completos de volver a descargar todo.
¿Es posible crear una imagen de Maven que almacene en caché mis dependencias para que no tengan que descargarse cada vez que uso la imagen para realizar una compilación?
Estoy ejecutando los siguientes comandos:
docker build -t my-maven .
docker run -it --rm --name my-maven-project -v "$PWD":/usr/src/mymaven -w /usr/src/mymaven my-maven mvn compile
Entiendo que todo lo que haga RUN
durante el proceso de construcción de la ventana acoplable se convierte en parte de la imagen resultante.
@Kim es el más cercano, pero aún no está del todo allí. No creo que agregar --fail-never
sea correcto, incluso si se hace el trabajo.
El comando de verify
hace que se ejecuten muchos complementos, lo cual es un problema (para mí). No creo que deban ejecutarse cuando lo único que quiero es instalar dependencias. También tengo una compilación de varios módulos y una subcompilación de javascript, lo que complica aún más la configuración.
Pero ejecutar solo verify
no es suficiente, porque si ejecuta la install
en los siguientes comandos, se usarán más complementos, lo que significa más dependencias para descargar. Maven se niega a descargarlos de lo contrario. Lectura relevante: Maven: Introducción al ciclo de vida de la compilación
Básicamente, tienes que encontrar qué propiedades deshabilitan cada complemento y agregarlas una por una, para que no rompan tu compilación.
WORKDIR /srv
# cache Maven dependencies
ADD cli/pom.xml /srv/cli/
ADD core/pom.xml /srv/core/
ADD parent/pom.xml /srv/parent/
ADD rest-api/pom.xml /srv/rest-api/
ADD web-admin/pom.xml /srv/web-admin/
ADD pom.xml /srv/
RUN mvn -B clean install -DskipTests -Dcheckstyle.skip -Dasciidoctor.skip -Djacoco.skip -Dmaven.gitcommitid.skip -Dspring-boot.repackage.skip -Dmaven.exec.skip=true -Dmaven.install.skip -Dmaven.resources.skip
# cache YARN dependencies
ADD ./web-admin/package.json ./web-admin/yarn.lock /srv/web-admin/
RUN yarn --non-interactive --frozen-lockfile --no-progress --cwd /srv/web-admin install
# build the project
ADD . /srv
RUN mvn -B clean install
pero algunos complementos no son tan fáciles de omitir. No soy un experto en maven (así que no sé por qué ignora la opción cli; podría ser un error), pero lo siguiente funciona como se espera para org.codehaus.mojo:exec-maven-plugin
<project>
<properties>
<maven.exec.skip>false</maven.exec.skip>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<id>yarn install</id>
<goals>
<goal>exec</goal>
</goals>
<phase>initialize</phase>
<configuration>
<executable>yarn</executable>
<arguments>
<argument>install</argument>
</arguments>
<skip>${maven.exec.skip}</skip>
</configuration>
</execution>
<execution>
<id>yarn run build</id>
<goals>
<goal>exec</goal>
</goals>
<phase>compile</phase>
<configuration>
<executable>yarn</executable>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
<skip>${maven.exec.skip}</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
tenga en cuenta el <skip>${maven.exec.skip}</skip>
explícito - otros complementos lo seleccionan de los parámetros de cli pero no este (ni -Dmaven.exec.skip=true
ni -Dexec.skip=true
trabajar por sí mismo)
Espero que esto ayude
Por lo general, no hay cambios en el archivo pom.xml
, pero otros cambios en el código src cuando se intenta iniciar la compilación de imágenes de la ventana acoplable. En tal circunstancia puedes hacer esto:
Para tu información:
FROM registry.cn-hangzhou.aliyuncs.com/acs/maven:3-jdk-8
MAINTAINER Eric Kim <[email protected]>
ENV PITBULL_EUREKA=/usr/src/app
RUN mkdir -p $PITBULL_EUREKA
WORKDIR $PITBULL_EUREKA
# add pom.xml only here, and download dependency
ADD pom.xml $PITBULL_EUREKA
RUN ["/usr/local/bin/mvn-entrypoint.sh", "mvn", "verify", "clean", "--fail-never"]
# now we can add all source code and start compiling
ADD . $PITBULL_EUREKA
RUN ["mvn", "package"]
EXPOSE 8888
CMD ["java", "-jar", "./target/eureka-0.0.1-SNAPSHOT.jar"]
Así que la clave es:
agregar el archivo
pom.xml
luego
mvn verify --fail-never
it, se descargarán las dependencias de maven.a continuación, agregue todo su archivo fuente e inicie su compilación (
mvn package
).
Cuando hay cambios en su pom.xml
o está ejecutando este script por primera vez, la ventana acoplable hará 1 -> 2 -> 3. Cuando no hay cambios en el archivo pom.xml
, la ventana acoplable saltará el paso 1、2 y hacer 3 directamente.
Este truco simple puede usarse en muchas otras circunstancias de administración de paquetes.
Resulta que la imagen que estoy usando como base tiene una imagen principal que define
VOLUME "$USER_HOME_DIR/.m2"
El resultado es que durante la compilación, todos los archivos se escriben en $USER_HOME_DIR/.m2
, pero debido a que se espera que sea un volumen, ninguno de esos archivos se conserva en la imagen del contenedor.
Actualmente, en Docker no hay forma de anular el registro de esa definición de volumen, por lo que sería necesario crear una imagen de experto por separado, en lugar de utilizar la imagen de experto oficial.
Si las dependencias se descargan después de que el contenedor ya está activo, entonces debe confirmar los cambios en este contenedor y crear una nueva imagen con los artefactos descargados.
Similar a la respuesta @Kim pero uso dependency:resolve
comando mvn. Así que aquí está mi completo Dockerfile:
FROM maven:3.5.0-jdk-8-alpine
WORKDIR /usr/src/app
# First copy only the pom file. This is the file with less change
COPY ./pom.xml .
# Download the package and make it cached in docker image
RUN mvn -B -f ./pom.xml -s /usr/share/maven/ref/settings-docker.xml dependency:resolve
# Copy the actual code
COPY ./ .
# Then build the code
RUN mvn -B -f ./pom.xml -s /usr/share/maven/ref/settings-docker.xml package
# The rest is same as usual
EXPOSE 8888
CMD ["java", "-jar", "./target/YOUR-APP.jar"]
Tuve este problema sólo un poco hace tiempo. Hay muchas soluciones en la web, pero la que funcionó para mí es simplemente montar un volumen para el directorio de módulos de Maven:
mkdir /opt/myvolumes/m2
luego en el Dockerfile:
...
VOLUME /opt/myvolumes/m2:/root/.m2
...
Hay mejores soluciones, pero no tan sencillas.
Esta publicación del blog hace un esfuerzo adicional para ayudarte a almacenar en caché todo:
https://keyholesoftware.com/2015/01/05/caching-for-maven-docker-builds/