2

I am using sbt-assembly to get fat jars and using sbt-docker to create and push docker images. My project is multi-module which has multiple web services, UI, database etc. Since my base docker image is big (800M), I want to create a docker image containing all the fat jars, so that I can easily test in cloud using one modest machine. I call this solution as All-FatJars-in-One (AFIO). I have trouble to build such AFIO docker image thus this post.

Suppose this multi-module project has module root and mod1, below is the build.scala:

val exeProjs = Seq(mod1)

lazy val root = Project("root", file(".")).
  enablePlugins(DockerPlugin).
  aggregate(exeProjs.map(_.project): _*).
  dependsOn(exeProjs.map(_ % "compile->test"): _*).
  settings(basicSettings: _*).
  settings(
    docker <<= docker dependsOn assembly,
    dockerfile in docker := {
      //get root artifact path like 
      // /home/me/root/target/scala-2.11/root-assembly-0.1-SNAPSHOT.jar 
      val parentArtifact = (assemblyOutputPath in assembly).value

      new Dockerfile {
        from("java:8")
        exeProjs.map(proj => {
          val projName = proj.id

          // fullPathToMod1Art will be like
          // /home/me/root/mod1/target/scala-2.11/mod1-assembly-0.1-SNAPSHOT.jar 
          fullPathToMod1Art = { NASTY parsing to get mo1 artifact }               

          val artifactTargetPath = s"/app/$projName/$artifact"
          addRaw(fullPathArt, artifactTargetPath)
      })
    }
  }

  imageNames in docker := Seq(
    ImageName("myaccount/root:v1")
  )
)

lazy val mod1 = Project("mod1", file("mod1")).
  enablePlugins(DockerPlugin).
  settings(basicSettings: _*).
  settings(
  libraryDependencies ++= Seq(spray_can, spray_routing, akka_actor, junit),

  docker <<= docker dependsOn assembly,

  dockerfile in docker := {
    val artifact = (assemblyOutputPath in assembly).value
    val artifactTargetPath = s"/app/${artifact.name}"
    new Dockerfile {
      from("java:8")
      add(artifact, artifactTargetPath)
      entryPoint("java", "-jar", artifactTargetPath)
    }
  },

  imageNames in docker := Seq(
    ImageName("myaccount/mod1:v1")
  )
)

Problems:

  1. above code does not work because the root module cannot find mod1 artifact even I have verified fullPathToMod1Art is correct for the generated mod1 artifact. I specified root dependsOn mod1 by compile->test since I don't know what other configurations are better to describe the need: root's docker image creation depends on mod1 fat jar generation.

  2. As you see, there is nasty path parsing to get mod1 artifact path in root module settings. There must be better way.

Questions:

If sbt-docker + sbt-assembly solution supports AFIO model, how to do it correctly so above two problems are solved elegantly? If they do not support, what other plugins can help?

Appreciate for any clue.

jiangok
  • 2,622
  • 3
  • 21
  • 26

1 Answers1

3

Since you want to use the assembly output from your subprojects you should make the docker task in your root project dependent on the assembly task in your subprojects:

docker <<= docker.dependsOn(assembly in mod1, assembly in mod2)

At the moment you have docker <<= docker dependsOn assembly which would generate a fat JAR for the root project.

You can also grab the assembly output path like this for your subprojects:

val jarFile = (outputPath in assembly in mod1).value

Hope this solves your problem.

  • "<<=" is deprecated in newer sbt, so i had to add these: dockerfile in docker := { val artifact: File = assembly.value val artifactTargetPath = (assemblyOutputPath in assembly).value – alex Aug 16 '19 at 16:25