hasdrubal
hasdrubal

Reputation: 1148

Docker multi-staged maven build split dependency resolve and compilation

I'm trying to setup a multi-staged dockerfile for my maven based java project. Here's what I'm using so far:

### STAGE 1: Build ###
FROM maven:3.6.1-jdk-8 as build

WORKDIR /usr/src/app

# Install app dependencies
COPY pom.xml .
RUN mvn dependency:go-offline

# Bundle app source
COPY src src
RUN mvn package

### STAGE 2: Production Environment ###
FROM jboss/wildfly:17.0.0.Final

COPY --from=build /usr/src/app/target/Appname.war /opt/jboss/wildfly/standalone/deployments/Appname.war

RUN /opt/jboss/wildfly/bin/add-user.sh admin admin123 --silent
CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0"]

The question is about the mvn commands. I see that mvn dependency:go-offline downloads some dependencies, which is great. But then mvn package downloads some more packages. Why? How can I have two steps:

EDIT

using mvn package -o, I get the following package not being found:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:2.6:resources (default-resources) on project monolith: Execution default-resources of goal org.apache.maven.plugins:maven-resources-plugin:2.6:resources failed: Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 or one of its dependencies could not be resolved: The following artifacts could not be resolved: org.apache.maven:maven-profile:jar:2.0.6, org.apache.maven:maven-repository-metadata:jar:2.0.6, org.apache.maven:maven-plugin-registry:jar:2.0.6, classworlds:classworlds:jar:1.1-alpha-2: Cannot access central (https://repo.maven.apache.org/maven2) in offline mode and the artifact org.apache.maven:maven-profile:jar:2.0.6 has not been downloaded from it before. -> [Help 1]

I think it's related to the build plugin in pom.xml. Any thoughts?

<build>
    <finalName>Monolith</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.2.3</version>
            <!--<configuration>-->
                <!--<webXml>src\main\webapp\WEB-INF\web.xml</webXml>-->
            <!--</configuration>-->
        </plugin>
    </plugins>
</build>

Upvotes: 3

Views: 1398

Answers (2)

ivant
ivant

Reputation: 3919

The maven dependency plugin has some limitations and so it doesn't download all the dependencies. This is mostly OK when you work locally, because a single mvn package command would do the trick.

But this is not well suited for maven running inside Docker container. After a lot of searching, today I stumbled upon the go-offline-maven-plugin. I tried it with the small project I'm using to test this and it worked.

Here is how to include it in your pom.xml:

<!-- ... -->
<build>
    <plugins>
        <plugin>
            <groupId>de.qaware.maven</groupId>
            <artifactId>go-offline-maven-plugin</artifactId>
            <version>1.2.1</version>
            <configuration>
                <dynamicDependencies>
                    <DynamicDependency>
                        <groupId>org.apache.maven.surefire</groupId>
                        <artifactId>surefire-junit4</artifactId>
                        <version>2.20.1</version>
                        <repositoryType>PLUGIN</repositoryType>
                    </DynamicDependency>
                </dynamicDependencies>
            </configuration>
        </plugin>
        <!-- ... -->
    </plugins>
    <!-- ... -->
</build>
<!-- ... -->

The dynamicDependencies are dependencies, which are not really present in any pom.xml, but are instead hard-coded in the plugins. The most common case is the surefire plugin, which loads the needed dependency depending on your tests (e.g. JUnit4/5, TestNG, etc.).

Lastly, you need to run this plugin from your Dockerfile. This should work:

### STAGE 1: Build ###
FROM maven:3.6.1-jdk-8 as build

WORKDIR /usr/src/app

# Install app dependencies
COPY pom.xml .
RUN mvn -e -B de.qaware.maven:go-offline-maven-plugin:resolve-dependencies

# Bundle app source
COPY src src
RUN mvn -o -e -B package

### STAGE 2: Production Environment ###
FROM jboss/wildfly:17.0.0.Final

COPY --from=build /usr/src/app/target/Appname.war /opt/jboss/wildfly/standalone/deployments/Appname.war

RUN /opt/jboss/wildfly/bin/add-user.sh admin admin123 --silent
CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0"]

Upvotes: 0

Karol Dowbecki
Karol Dowbecki

Reputation: 44952

You are most likely affected by MDEP-82 go-offline / resolve-plugins does not resolve all plugin dependencies bug which is currently unresolved.

As per this comment in the MDEP-82 issue this can potentially be fixed by specifying maven-dependency-plugin version instead of using the default one:

then define explicitiely the maven-dependency-plugin version used for go-offline to not depend on default version defined inside Maven:

mvn -s settings.xml org.apache.maven.plugins:maven-dependency-plugin:2.8:go-offline

Upvotes: 1

Related Questions