4

I'm building a Docker image with a fat jar. I use the sbt-assembly plugin to build the jar, and the sbt-native-packager to build the Docker image. I'm not very familiar with SBT and am running into the following issues.

  1. I'd like to declare a dependency on the assembly task from the docker:publish task, such that the fat jar is created before it's added to the image. I did as instructed in the doc, but it's not working. assembly doesn't run until I invoke it.

    publish := (publish dependsOn assembly).value

  2. One of the steps in building the image is copying the fat jar. Since assembly plugin creates the jar in target/scala_whatever/projectname-assembly-X.X.X.jar, I need to know the exact scala_whatever and the jar name. assembly seems to have a key assemblyJarName but I'm not sure how to access it. I tried the following which fails.

    Cmd("COPY", "target/scala*/*.jar /app.jar")

Help!

Community
  • 1
  • 1
Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219

1 Answers1

8

Answering my own questions, the following works:

enablePlugins(JavaAppPackaging, DockerPlugin)

assemblyMergeStrategy in assembly := {
  case x => {
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    val strategy = oldStrategy(x)
    if (strategy == MergeStrategy.deduplicate)
      MergeStrategy.first
    else strategy
  }
}

// Remove all jar mappings in universal and append the fat jar
mappings in Universal := {
  val universalMappings = (mappings in Universal).value
  val fatJar = (assembly in Compile).value
  val filtered = universalMappings.filter {
    case (file, name) => !name.endsWith(".jar")
  }
  filtered :+ (fatJar -> ("lib/" + fatJar.getName))
}

dockerRepository := Some("username")

import com.typesafe.sbt.packager.docker.{Cmd, ExecCmd}
dockerCommands := Seq(
  Cmd("FROM", "username/spark:2.1.0"),
  Cmd("WORKDIR", "/"),
  Cmd("COPY", "opt/docker/lib/*.jar", "/app.jar"),
  ExecCmd("ENTRYPOINT", "/opt/spark/bin/spark-submit", "/app.jar")
)

I completely overwrite the docker commands because the defaults add couple of scripts that I don't need because I overwrite the entrypoint as well. Also, the default workdir is /opt/docker which is not where I want to put the fat jar. Note that the default commands are shown by show dockerCommands in sbt console.

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
  • Yep. This is the example from the documentation. A small hint: You can remove the `DockerPlugin` in `enablePlugins(...)`. The `JavaAppPackaging` enables it by default. – Muki Mar 06 '17 at 09:05
  • @Muki Not exactly from the doc. The doc uses deprecated `jarName` and doesn't have an example of fat jar as a Docker container, but only individual pieces. But yes, I got the idea from the doc. Can you say if there's a way to stop generating the scripts that serve as default entrypoint? I don't include them but they still get generated in `opt/docker/bin` locally. – Abhijit Sarkar Mar 07 '17 at 05:10