1
votes

I'm trying to build a scala project with docker Multi-Stage ability.

For starter, this is my dockerfile:

FROM maven:3.6.0-jdk-11-slim AS maven
RUN apt-get update
WORKDIR /build
COPY pom.xml .
RUN mvn -B de.qaware.maven:go-offline-maven-plugin:resolve-dependencies
COPY src src
RUN mvn -B -o install spring-boot:repackage

FROM openjdk:11.0.6
WORKDIR /opt/app
COPY --from=maven /build/target/app.jar app.jar
CMD ["java", "-jar", "/opt/app/app.jar"]
EXPOSE 8080

I noticed that after finishing the resolve-dependencies part, maven still trying to download dependencies on install stage. The errors that I get are related to the scala-maven-plugin that looking for non-existing dependencies that didn't fetched in the resolving stage. The errors looks like this:

Failed to execute goal net.alchim31.maven:scala-maven-plugin:3.4.0:compile (default) on project app: wrap: org.apache.maven.artifact.resolver.ArtifactNotFoundException: Cannot access ... in offline mode and the artifact org.scala-lang:scala-compiler:jar:2.11.12 has not been downloaded from it before.

Even adding this dependency isn't enough because it fails on another dependecies.

The plugin in the POM looks like that:

        <plugin>
            <groupId>net.alchim31.maven</groupId>
            <artifactId>scala-maven-plugin</artifactId>
            <version>3.4.0</version>
            <executions>
                <execution>
                    <goals>
                        <!-- Need to specify this explicitly, otherwise plugin won't be called when doing e.g. mvn compile -->
                        <goal>compile</goal>
                        <goal>testCompile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <args>
                    <!-- work-around for https://issues.scala-lang.org/browse/SI-8358 -->
                    <arg>-nobootcp</arg>
                    <arg>-Yresolve-term-conflict:package</arg>
                </args>
                <scalaVersion>${scala.version}</scalaVersion>
            </configuration>
        </plugin>

Seems like the plugin doesn't stop there and download everything again. Thanks guys..

2
Why building why maven? Why building inside docker? Looks like x/y question - cchantep
@cchantep I build inside docker to take advantage of the multi-stage ability to avoid downloading all the libraries every build. For the maven part - why not using maven? - ChopChop
The question is not about multistage but docker itself. Building inside add notable overhead that is rarely acceptable for incremental build. As for maven ... SBT is the first citizen build tool for Scala ... - cchantep

2 Answers

0
votes

Like there is a comment on your question it is better to use sbt as a first citizen build tool for Scala. Particularly I suggest using the sbt-native-packager in conjunction with the plugins JavaAppPackaging and DockerPlugin to create the docker image without a Dockerfile. There are some tutorials to create it on the web. Basically, you will need something like these lines on your build.sbt file (example from my project).

enablePlugins(JavaAppPackaging, JavaServerAppPackaging, DockerPlugin, AshScriptPlugin)

// ####### Dockerfile settings #######
import NativePackagerHelper._

packageName in Docker := packageName.value
version in Docker := version.value
dockerExposedPorts := List(8001, 2551)
dockerLabels := Map("user" -> "[email protected]")
dockerBaseImage := "openjdk:jre-alpine"
dockerRepository := Some("docker.user.name")
defaultLinuxInstallLocation in Docker := "/usr/local"
daemonUser in Docker := "daemon"
mappings in Universal ++= directory( baseDirectory.value / "src" / "main" / "resources" )
// ####### Dockerfile settings #######

and at the project/plugins.sbt file:

addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.6")

Then you execute the following commands on your console in order to create the Dockerfile at target/docker/stage/Dockerfile.

sbt docker:stage
sbt docker:publishLocal
0
votes

Finally, to solve this issue I used this plugin for 'go-offline' instead of maven's:

        <plugin>
            <groupId>de.qaware.maven</groupId>
            <artifactId>go-offline-maven-plugin</artifactId>
            <version>1.2.8</version>
        </plugin>

Using it with this command:

mvn -B de.qaware.maven:go-offline-maven-plugin:resolve-dependencies

Also added to scala-maven-plugin this configuration which disable the incremental compile dependencies:

        <configuration>
            <recompileMode>all</recompileMode>
        </configuration>

So the full plugin looks like this:

    <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <version>4.4.0</version>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                    <goal>testCompile</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <recompileMode>all</recompileMode>
        </configuration>
    </plugin>